Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions BUGFIX_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@
---
## 2026-08-11

### BUG · 未评分职位卡被错误显示为 0 分

**错误**
切换 CV 后,大量没有当前 CV 精评分的缓存职位在列表中显示为 0 分,看起来像是模型给出了最低匹配结果。

**原因**
后端正确返回 `score: null`,但前端评分徽章先执行 `Number(null)`;JavaScript 会将其转换为数值 `0`,导致“未评分”和“真实 0 分”无法区分。

**解决方案**
评分徽章在数值转换前显式识别 `null` 和 `undefined`,未评分显示灰色长横线,真实数值 0 继续显示为 0。

**结果**
新增前端回归测试覆盖未评分与真实 0 分的区分;前端语法检查、Ruff、Python 编译和完整 pytest(248 tests)均通过。

### BUG · 已删除 Gmail 邮件导致增量同步游标永久停滞

**错误**
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

### Bug Fixes

- **Unassessed job cards no longer appear as zero-score matches** (`templates/index.html`)
Job cards whose current-CV score is `null` now show a gray em dash instead of being coerced to `0` by JavaScript. Genuine numeric zero scores still display as zero, preserving the distinction between "not assessed" and "assessed with no match".

- **Deleted Gmail messages no longer stall incremental sync** (`email_sync.py`)
When Gmail history references a message that has already disappeared, a `messages.get` 404 is now treated as a terminal missing-message condition rather than a retryable fetch failure. The sync skips that message and saves Gmail's latest `historyId`, while authentication, rate-limit, server, and network errors still hold the cursor for a later retry.

Expand Down
5 changes: 3 additions & 2 deletions jobradar/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2095,8 +2095,9 @@ <h4 class="text-sm font-bold uppercase tracking-wide text-gray-500 dark:text-gra
return "bg-red-400";
}
function scoreBadge(s) {
const numeric = Number(s);
const display = Number.isFinite(numeric) ? Math.round(numeric) : "?";
const missing = s === null || s === undefined;
const numeric = missing ? NaN : Number(s);
const display = missing ? "—" : Number.isFinite(numeric) ? Math.round(numeric) : "?";
return `<span class="inline-flex items-center justify-center w-11 h-11 rounded-full text-white text-sm font-bold font-mono leading-none tabular-nums flex-shrink-0 ${scoreColor(s)}">${display}</span>`;
}
function normalizedScore(s) {
Expand Down
13 changes: 13 additions & 0 deletions tests/test_search_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,16 @@ def test_start_search_keeps_existing_jobs_until_sse_updates_them():
assert "JOBS = []" not in start_search
assert "activeKey = null" not in start_search
assert "if (existing >= 0) JOBS[existing] = job;" in html


def test_score_badge_distinguishes_unassessed_from_real_zero():
html = (Path(__file__).parents[1] / "jobradar" / "templates" / "index.html").read_text(
encoding="utf-8"
)
score_badge = html.split("function scoreBadge(s)", 1)[1].split(
"function normalizedScore", 1
)[0]

assert 'const missing = s === null || s === undefined;' in score_badge
assert 'const display = missing ? "—"' in score_badge
assert 'Number.isFinite(numeric) ? Math.round(numeric) : "?"' in score_badge
Loading