更新日誌
GitHub每一項重大變更,逐版記錄。同一份檔案隨儲存庫發布,並已翻譯為全部 19 種語言。
[1.59.9] — 2026-05-21
fix(ux): UX-A5-r4 (v1.59.9) — Help TOC 捲動監聽偵錯標記 data-toc-spy="active" + 行為鎖測試。 第 6 個週期。同步初始繪製 + 雙 rAF 重新計算 + resize 監聽器 + hashchange 清理。(UX-A5-r4)
[1.59.8] — 2026-05-21
fix(ux+api): v1.59.8 — UX-A5-r3 + NEW-F1-sub (HIGH + LOW 合併)。 FINAL-REGRESSION-v1.59.7 報告授權的 doctrine 例外。UX-A5-r3: #/help 將 IntersectionObserver 替換為帶 rAF 節流的 scroll 監聽器。NEW-F1-sub: 中介軟體將 /api/* 的原始 .. 以 404 JSON 拒絕。(UX-A5-r3 · NEW-F1-sub)
[1.59.7] — 2026-05-20
fix(api): NEW-D3-cache (v1.59.7) — GET /api/cv 傳送 Cache-Control: no-store。 CV 是使用者主要工件,始終重新驗證。(NEW-D3-cache)
[1.59.6] — 2026-05-20
feat(a11y): NEW-D2-motion (v1.59.6) — 尊重 prefers-reduced-motion: reduce。 新 @media 區塊停用動畫、過渡和 scroll-behavior。(NEW-D2-motion)
[1.59.5] — 2026-05-20
fix(api): NEW-F1 (v1.59.5) — 未知 /api/* 在任何 HTTP 動詞上都回傳 JSON 404。 app.get → app.all。(NEW-F1)
[1.59.4] — 2026-05-20
fix(ui): NEW-OR1 (v1.59.4) — #/config Active/Keys 晶片消除競態。 原子 replaceChildren + 在途權杖 + 上次良好狀態快取。(NEW-OR1)
[1.59.3] — 2026-05-20
fix(ux): UX-A5-r2 (v1.59.3) — 強化 #/help 滾動監聽。 rootMargin 可見帶從 10 % 擴展到 25 % + 掛載時計算初始狀態。(UX-A5-r2)
[1.59.2] — 2026-05-20
fix(ui): v1.59.2 — Active/Keys 晶片:計數正確、供應方名稱大寫、不再重疊。 (post-v1.59.1 hotfix)
[1.59.1] — 2026-05-20
fix(test): v1.59.1 — NEW-D1 守衛接受 UX-A11 打磨過的 ES 文案。 (v1.59.1)
[1.59.0] — 2026-05-20
feat(ui): UX-A14 (v1.59.0) — 行動裝置(≤ 420 px)稽核通過。 新的 @media (max-width: 420px) 區塊中包含 5 項修復。(UX-A14)
[1.58.65] — 2026-05-20
test(ui): UX-A2 (v1.58.65) — Modes 結構化欄位表單回歸鎖測試。 新測試保護 v1.54.3 實作免受回歸。(UX-A2)
[1.58.64] — 2026-05-20
fix(i18n): UX-A11 (v1.58.64) — es/pt-BR 文案打磨。 英語借用詞替換為母語等價表達。(UX-A11)
[1.58.63] — 2026-05-20
fix(ui): UX-A15 (v1.58.63) — Dashboard Pipeline 磁貼獲得視覺主要強調。 Pipeline 磁貼現在帶有強調邊框、更大的圖示和加粗的標籤。(UX-A15)
[1.58.62] — 2026-05-20
feat(ui): UX-A9 (v1.58.62) — API keys 分頁頂部的 sticky 摘要晶片。 #/config → API keys 分頁頂部新增 sticky 晶片,顯示活動供應方和已配置金鑰數量。(UX-A9)
[1.58.61] — 2026-05-20
docs(readme): UX-A8 (v1.58.61) — 在所有 8 個 README 中新增首次執行清理章節。 現在記錄了在首次掃描前清理兩個 QA 測試夾具 URL 的 make clean-test-fixtures 步驟。(UX-A8)
[1.58.60] — 2026-05-20
feat(ui): UX-A12 (v1.58.60) — 通知抽屜支援全部清除 + 單條關閉。 通知面板新增全域清除按鈕和每條 × 按鈕。(UX-A12)
[1.58.59] — 2026-05-20
feat(ui): UX-A13 (v1.58.59) — #/health 失敗行的可執行 “Fix →” CTA。 FAIL/OPTIONAL 行現在顯示直接跳轉到相應配置選項卡的 ghost 按鈕。(UX-A13)
[1.58.58] — 2026-05-20
fix(ux): UX-A10 (v1.58.58) — 防止 #/cv 未儲存的編輯遺失。 瀏覽器關閉(beforeunload)和 SPA 內導航(hashchange)在髒緩衝區時顯示本地化確認對話框。(UX-A10)
[1.58.57] — 2026-05-20
test(ui): UX-A7 (v1.58.57) — cost-line 自動刷新契約的回歸鎖測試。 新增靜態測試,確保 providers-changed 事件被派發、被訂閱,以及所有 advisor 視圖都呼叫 UI.providerCostHint。(UX-A7)
[1.58.56] — 2026-05-20
fix(a11y): UX-A4 (v1.58.56) — .lang-btn 達到 WCAG 2.5.8 最小觸控目標尺寸。 修復前語言按鈕高 23–25 px,低於 24×24 px 標準。現在透過 min-height: 28px + min-width: 28px 達到 WCAG 2.2 AA 合規。(UX-A4)
[1.58.55] — 2026-05-20
feat(ui): UX-A3 (v1.58.55) — Dashboard 活動供應方晶片。 #/dashboard 主區現在顯示當前活動的 LLM 供應方(⚡ Live evals: Anthropic claude-sonnet-4-6 或 📋 Manual prompt mode)。在 #/config 變更 LLM_PROVIDER 或分頁重新獲得焦點時自動更新。(UX-A3)
[1.58.54] — 2026-05-20
fix(ux): UX-A1 (v1.58.54) — Deep 簡報結構防禦性警告。 當儲存的簡報缺少 6 個標準章節(Company snapshot / Engineering culture / Recent news / Glassdoor / Interview process / Negotiation leverage)中至少 3 個時,public/js/views/deep.js 會在內容前顯示一個非阻塞警告並連結到參考文件。這是 UI 層防護;根本的提示層修復位於父專案。(UX-A1)
[1.58.53] — 2026-05-20
fix(ux): UX-A6 — 所有 saved-card 通過單一 renderSavedCard() 輔助函式渲染。 保證任何渲染路徑下都有 <span>+<time> 結構。948 → 949 單元。(UX-A6)
[1.58.52] — 2026-05-20
fix(ux): UX-A5 — #/help TOC 捲動追蹤現在能正確觸發。 v1.58.45 的 setTimeout(0) 在路由掛載前就執行了。修正:直接參照 headings + 雙重 requestAnimationFrame。947 → 948 單元。(UX-A5)
[1.58.51] — 2026-05-20
chore(docs): v1.58.51 — v1.58.37 → v1.58.50 週期(14 個版本)的最終清理。 不改程式碼。qa/ 重新整理(所有版本固定文件移到 archive/v158-cycle/);6 個 perennial 留在根目錄。REGRESSION-FINAL §13 記錄 v1.58.37→.50 的全部不變量。基線不變(947/947)。(housekeeping)
[1.58.50] — 2026-05-20
docs: DOC-1 — qa/REGRESSION-FINAL.md 新增 §5a(伺服器錯誤本文按設計保持英文政策)。 關閉 NEW-D4 為 not-a-finding。完成 FIX-PROMPT-FINAL-EXHAUSTIVE.md 的 v1.58.37 → v1.58.50 佇列(14 個版本)。 946 → 947 單元。(DOC-1)
[1.58.49] — 2026-05-20
chore(tooling): TOOL-1 — 新增 make clean-test-fixtures 與腳本,用於從父專案 data/pipeline.md 移除 example.com 行。 支援 --dry-run。4 個 CI-isolated 測試。942 → 946 單元。(TOOL-1)
[1.58.48] — 2026-05-20
fix(ux/onboarding): UX-D-B — 當使用者仍使用預設範本資料時,#/dashboard 頂部顯示全域警告橫幅。 /api/health 偵測到 Profile customized: false 時顯示 .hero-banner--warning。新 i18n 鍵 onboarding.fixtureWarning + onboarding.fixProfile × 8。941 → 942 單元。(UX-D-B)
[1.58.47] — 2026-05-20
fix(ux/naming): UX-D-C — 頂列 “Quick scan” 重新命名為 開啟 Scan(它只是導航,並不真正啟動掃描)。 8 語言更新。940 → 941 單元。(UX-D-C)
[1.58.46] — 2026-05-20
fix(ux): UX-D-D — #/apply 清單將 {company}-{role} 替換為從 URL/JD 推導的 slug。 此前占位符按字面顯示。新 extractSlugs + substitutePlaceholders 辨識 Greenhouse/Lever/Ashby/Workable/SmartRecruiters/Workday。退回 [company]/[role]。939 → 940 單元。(UX-D-D)
[1.58.45] — 2026-05-20
fix(ux): UX-D-K — #/help 的 TOC 捲動追蹤高亮目前章節。 IntersectionObserver 把 .toc-current 套用到目前可見 H2 對應的 TOC 連結。938 → 939 單元。(UX-D-K)
[1.58.44] — 2026-05-20
fix(ux): UX-D-L — #/deep 中開啟的 Saved-research 簡報新增內聯 × 關閉按鈕。 此前只能捲動或離開頁面才能關閉。新 i18n 鍵 deep.closeBrief × 8。937 → 938 單元。(UX-D-L)
[1.58.43] — 2026-05-20
fix(ux): UX-D-F — #/evaluate 空白送出時顯示專用的在地化 toast。 之前與「過短」是同一條訊息。新 i18n 鍵 eval.emptyJd × 8。936 → 937 單元。(UX-D-F)
[1.58.42] — 2026-05-20
fix(ux): UX-D-J — 所有 advisor 頁面的 ETA 晶片一致性。 此前僅 #/auto 顯示 “⏱ ~1–2 min”。現 #/evaluate、#/deep 與 5 個 mode 頁面同樣顯示 ⏱ ~30s(新 i18n 鍵 advisor.eta × 8)。935 → 936 單元。(UX-D-J)
[1.58.41] — 2026-05-20
fix(ux/truthfulness): UX-D-I — 費用提示在分頁重新可見 + providers-changed 事件時重新拉取。 之前僅取一次,在另一分頁變更提供者後舊值會持續顯示。934 → 935 單元。(UX-D-I)
[1.58.40] — 2026-05-20
fix(ux/docs): UX-D-H — 回歸鎖:每個可見的 career-ops.org/docs/... 深層連結必須保持可點擊。 新 tests/external-doc-links.test.mjs 校驗 views/.js 與 docs/help/.md。932 → 934 單元。(UX-D-H)
[1.58.39] — 2026-05-20
fix(ux): NEW-D2 — 儀表板頂部新增 Refresh 按鈕並提供明確的回饋 toast。 與連線橫幅的 Refresh 不同;就地重新取數 + 重新渲染,不重新整理頁面。2 個新 i18n 鍵。931 → 932 單元。(NEW-D2)
[1.58.38] — 2026-05-20
fix(a11y): NEW-D3 (WCAG 4.1.2) — #/tracker 搜尋輸入獲得與 placeholder 不同的在地化 aria-label。 此前僅有 placeholder,螢幕閱讀器無法聽到用途。新 i18n 鍵 track.searchAria × 8 語言,與 placeholder 不同。930 → 931 單元。(NEW-D3)
[1.58.37] — 2026-05-20
fix(i18n): NEW-D1 — #/pipeline H1 在 es/pt-BR/ru 上在地化 + 修正 2 處 RU 標題洩漏。 新 tests/i18n-no-latin-leaks.test.mjs 同時抓出 contacto.title 與 health.title 的 RU 洩漏。928 → 930 單元。(NEW-D1)
[1.58.36] — 2026-05-20
chore(docs): v1.58.36 — v1.58.x 週期收尾的完整文件清理。 不改程式碼。(1) qa/:3 個版本固定快照(REGRESSION-END-TO-END-v1.58.16/33/35.md)移至 qa/archive/v158-cycle/。(2) REGRESSION-FINAL.md 新增 §12(v1.58.4 → v1.58.35 全部不變量)。(3) UX-AUDIT-PROMPT.md 新增 30 行已關閉條目。(4) docs/architecture/ 更新(FRONTEND 抽屜、TESTING 合計 928/62/20/23)。(5) CLAUDE.md 新增「v1.58.x 週期的硬經驗教訓」章節。(6) README ×8 新增「通知 🔔」行 + 修正過時的測試計數。基線無變化。(housekeeping)
[1.58.35] — 2026-05-20
fix(ui): v1.58.35 — 通知抽屜不再自動開啟 + 說明新增 §18「通知」(使用者回報)。 v1.58.34 bug:.notif-drawer { display: flex } 戰勝了 UA 的 [hidden] { display: none }。修正:顯式新增 .notif-drawer[hidden] { display: none }。抽屜僅在點擊鈴鐺時開啟。8 種語言的說明新增 §18(類別表 + 鍵盤)。927 → 928 單元。(使用者回報)
[1.58.34] — 2026-05-20
feat(ui): v1.58.34 — 通知抽屜(完全收口 U-13)。 在 v1.58.33 擷取之上:新 UI.onToast(fn)、頂列 🔔 + 未讀徽章、右側 <aside role="dialog">,在地化標題 / 空狀態 / 條目(notif.* × 8)。Esc + 關閉 + 再次點擊鈴鐺關閉。926 → 927 單元。(U-13 follow-up)
[1.58.33] — 2026-05-20
fix(ux): U-13 + U-14 + U-15 — toast 日誌(上限 50 + UI.getToastHistory())+ .page-header h1 + p 兜底規則 + #/cv 未儲存指示器。 收尾 v1.58.x 系列。新增 i18n 鍵 cv.unsaved × 8 語言。925 → 926 單元。(U-13/U-14/U-15)
[1.58.32] — 2026-05-20
fix(ux): U-12 — #/help TOC 過濾輸入框獲得 min-width: 16ch 以避免 KO/JA 預留位被截斷。 新增 .help-toc__filter 類別。924 → 925 單元。(U-12)
[1.58.31] — 2026-05-20
fix(ux): U-11 — Tracker Legitimacy 欄表頭新增在地化資訊 ⓘ + tooltip 解釋 High/Caution/Suspicious 等級。 新增 i18n 鍵 track.col.legitimacy.help × 8 語言。923 → 924 單元。(U-11)
[1.58.30] — 2026-05-20
fix(ux): U-10 — data/applications.md 為空時,Tracker 的 Normalize / Dedup / Merge 按鈕停用。 在地化提示 (track.fixEmpty × 8 語言) 說明原因。922 → 923 單元。(U-10)
[1.58.29] — 2026-05-20
fix(ux): U-9 — #/pipeline 計數 ↔ 過濾列在窄螢幕垂直堆疊。 新 .pipeline-controls 類別配合 @media (max-width: 720px) 把過濾拉伸到 100% 寬度。921 → 922 單元。(U-9)
[1.58.28] — 2026-05-20
fix(ux): U-8 — 7 個 mode 頁面的生成提示詞區塊預設折疊。 包裹在 <details class="prompt-block"> 中;摘要顯示在地化的 “Show prompt (N lines)”(prompt.show / prompt.lines × 8)。Copy + Run-live 仍可見。920 → 921 單元。(U-8)
[1.58.27] — 2026-05-20
fix(ux): U-7 — verify-pipeline.mjs 的 === ASCII 分隔線從結果視窗中移除。 在處理函式內透過正則 ^={10,}$ 預先剝離。919 → 920 單元。(U-7)
[1.58.26] — 2026-05-20
fix(ux): U-6 — #/scan 的 “Active companies N/M” 晶片透過 tooltip + aria-label 解釋 N 與 M。 新增 i18n 鍵 scan.activeCo.help × 8 語言。918 → 919 單元。(U-6)
[1.58.25] — 2026-05-20
fix(ux/ia): U-5 — 儀表板 CTA 去重(移除 header 的 Open Pipeline 按鈕和 Quick-action 中 Scan all sources 卡片)。 側邊欄與 hero 已涵蓋兩條路由;v1.58.3 QA 的 4× Pipeline / 4× Scan 減為各 2×。917 → 918 單元。(U-5)
[1.58.24] — 2026-05-20
fix(ux): U-4 — 錯誤 toast 把 “(METHOD /path · HTTP NNN)” 後綴塞入折疊的 <details> 中。 技術細節仍保留在 DOM 中(BUG-006 不變量),但標題更清爽。新增 i18n 鍵 toast.details × 8 語言。916 → 917 單元。(U-4)
[1.58.23] — 2026-05-20
fix(ux): U-3 — #/followup 的 lastContact 預留位文字改為今日 − 14 天動態計算。 固定 2026-04-21 會隨時間老化;現在在渲染時透過 new Date() + setDate(getDate() - 14) 產生 ISO YYYY-MM-DD。915 → 916 單元。(U-3)
[1.58.22] — 2026-05-20
fix(ux): U-2 — #/auto 的 H1 不再因前導 ✨ 而換行至兩行。 把 ✨ 從 auto.title 拆出到獨立 <span class="page-icon" aria-hidden="true">;.page-header--icon 用 CSS grid 為圖示設獨立欄。914 → 915 單元。(U-2)
[1.58.21] — 2026-05-20
fix(ux): U-1 — #/cv 的 H1 + 副標題與其它頁面統一(按設計撤回 v1.56.0 UX-9 chip)。 移除 .cv-breadcrumb chip,改用 <h1 class="page-title"> + <p class="page-subtitle">。單 <h1> 不變量保留。913 → 914 單元。(U-1)
[1.58.20] — 2026-05-20
fix(i18n/platform): I-6 — 側欄底部快捷鍵提示在 Mac 上顯示 ⌘K、其它系統顯示 Ctrl+K,動詞在地化。 之前在任何平台和語言下都顯示英文字面 CTRL+K — search。top.langhint 現採 {hotkey} — 搜尋 形式;applyFooterHotkey() 依 navigator.platform 取代 {hotkey}。915 → 916 單元。(I-6)
[1.58.19] — 2026-05-20
fix(i18n): I-4 — 俄語 #/followup 不再洩漏 cadence / follow-up。 RU followup 字串(H1、提示)中混有 cadence、follow-up、scope、timeline。已替換為俄語在地表達。914 → 915 單元。(I-4)
[1.58.18] — 2026-05-20
fix(i18n): I-3 — 說明 TOC 項目 2/5/13/14 在非拉丁語言下消除英文殘留。 修正前部分本地化說明文件中仍含有 ## 2. App settings & API keys、## 5. Portals & Sources、## 13. Mode prompts、## 14. Apply checklist。現 8 種語言全部完全本地化。913 → 914 單元。(I-3)
[1.58.17] — 2026-05-20
fix(i18n): I-2 — Saved-research 卡片日期改用 Intl.RelativeTimeFormat 按語言在地化。 public/js/views/deep.js 的 formatRelative() 之前在任何語言下都硬寫英文 today / 1d ago / Nd ago。改為 Intl.RelativeTimeFormat(I18n.getLang(), { numeric: 'auto' }) — 瀏覽器原生本地化字串(「今天/昨天/N 天前」、「сегодня/вчера」等)。超過 7 天的日期回退到 Intl.DateTimeFormat(locale, { dateStyle: 'medium' })。912 → 913 單元。(I-2)
[1.58.16] — 2026-05-20
fix(ui): 品牌按鈕滑鼠停留閃爍(使用者回報)。 原因:.btn-primary / .btn-danger 預設背景為 linear-gradient(...),:hover 換成純色 var(--rausch-dark)。CSS 無法在漸層↔純色間補間,180ms transition: background 會「跳動」,使用者看到白/粉色閃光。修正 public/css/app.css:懸停時保留漸層,改用 filter: brightness(0.92) 加深 — filter 在所有瀏覽器都能平滑補間。.btn 的 transition 清單新增 filter var(--transition),讓加深帶動畫效果。911 → 912 單元。(使用者回報)
[1.58.15] — 2026-05-20
fix(a11y/i18n): I-1 — 頂列搜尋的 aria-label 和視覺隱藏 <label> 現已本地化。 此前所有 8 種語言下,螢幕閱讀器聽到的都是英文 aria-label。public/js/app.js 新增通用 data-i18n-aria-label 鉤子 — applyI18n() 在每次語言切換時更新 aria-label,與 data-i18n / data-i18n-placeholder 對稱。新增 2 個 i18n 鍵(top.search.aria, top.search.label)覆蓋 8 種語言。鉤子可被任何未來控制元件重複使用。910 → 911 單元。(I-1)
[1.58.14] — 2026-05-20
fix(ux): M-9 — 連線橫幅的「重新整理」按鈕現在提供回饋(之前為靜默重新載入)。 在 v1.58.13 之前,處理器直接呼叫 location.reload()。現在點擊會立即彈出「重新整理中…」的 toast,設定 sessionStorage['refreshedToast'],把按鈕設為 disabled 防止雙擊堆疊,並把 reload 延遲 200ms 讓 toast 繪製。下次啟動時 app.js 偵測到旗標,彈出成功 toast「已重新整理」。在 8 種語言中新增 2 個 i18n 鍵(common.refreshing, common.refreshed)。909 → 910 單元。(M-9)
[1.58.13] — 2026-05-20
fix(ux): M-8 — #/apply 清單變為可互動。 在 v1.58.13 之前,「▶ 產生清單」把 0…7 號項目以等寬 <pre> 區塊呈現 — 唯讀、無法勾選。現在每個項目渲染為真正的 <input type="checkbox">,外層包裹 <label>(點擊區域為整行,WCAG 2.5.5)。狀態依 URL 持久化至 localStorage['applyChecklist:'+slug] — 勾選 3 項 → 重新整理 → 3 項仍維持。按鈕:複製未勾選項(將尚未完成的項目以 - markdown 條列輸出)與 重設。在 8 種語言中新增 5 個 i18n 鍵(apply.checklist.copyUnchecked, resetBtn, copied, copyFailed, reset)。解析器找不到項目時有防禦性退路。908 → 909 單元。(M-8)
[1.58.12] — 2026-05-20
fix(ux): M-7 — 成本提示跟隨當前活躍提供者(OpenRouter 不再回退到偽造數字)。 UI.providerCostHint() 已透過 /api/status/providers 達成 provider-aware,但 public/js/api.js 的對映只列出 anthropic/gemini/openai/qwen。v1.57.0 加入 OpenRouter 為第 5 個提供者後,會落到通用回退 0.03 並顯示小寫字面值 openrouter。現在 EST 加入 openrouter: null(由路由選擇模型,費用因此而異),=== null 分支輸出本地化的「cost varies (router picks)」,而非誤導性的 ~$0.03/eval。NAME 加入 openrouter: 'OpenRouter'。新增 i18n 鍵 cost.varies 覆蓋 8 種語言。907 → 908 單元。(M-7)
[1.58.11] — 2026-05-20
fix(ux): M-4 — 已儲存研究卡片的標題↔日期間距改為結構化 CSS(原為內聯 margin)。 v1.58.3 MASTER 回歸確認部分卡片顯示為 software-engineer-generaltoday(標題與日期之間無空格),其餘正常。原因:舊程式依賴兩個裸 <span> 間的 style="margin-left: 8px",在某些項目中崩塌。修正:public/js/views/deep.js — 將兩個 <span> 替換為 .saved-card__title + 語義化 <time class="saved-card__date" datetime="…">,外層包裹 .saved-card flex 容器。間距由 gap: var(--space-2, 8px) 控制 → 不再崩塌,同時取得 <time> 的 a11y/SEO 語義。906 → 907 單元。(M-4)
[1.58.10] — 2026-05-20
fix(ux): M-2 — 在開啟任何結果模態框前先清空進度 toast。 在 #/cv 點擊 sync-check 時,「Running cv-sync-check.mjs…」toast 仍留在右下角,而結果模態框已經打開 — 二者搶奪注意,在窄螢幕上視覺重疊。Health 頁的 Doctor / verify-pipeline 按鈕原本就在 UI.modal() 前明確呼叫 UI.dismissToast();cv.js 的 sync-check 是唯一遺漏的入口。修正:public/js/api.js — UI.modal() 現在將 dismissToast() 作為首個可執行陳述呼叫(邊界處的縱深防禦)。同時把 cv.js 中硬編碼的英文字串改為 t('cv.syncCheckRunning') / t('cv.syncCheck'),滿足 BUG-008 不變量(模態框標題 == 本地化按鈕標籤)。在 8 種語言中新增兩個 i18n 鍵。905 → 906 單元。(M-2)
[1.58.9] — 2026-05-20
fix(a11y): M-1 — 在表單欄位上恢復可見的 :focus-visible 焦點環(WCAG 2.4.7 Level AA)。 v1.58.3 MASTER 回歸確認 getComputedStyle(focusedInput) 回傳 outline: rgb(255,255,255) none 1.5px — none 關鍵字將每個欄位的焦點環寬度塌陷為 0 px。根因:.input, .textarea, .select { outline: none } 與 .searchbar input { outline: none } 的基礎規則優先級高於全域 *:focus-visible,悄悄消除了每頁 88 個可聚焦元素的鍵盤焦點環。修正於 public/css/app.css — 明確新增 .input:focus-visible/.textarea:focus-visible/.select:focus-visible 與 .searchbar input:focus-visible 規則,使用 outline: 2px solid var(--rausch) + 半透明 box-shadow;滑鼠焦點(:focus)保持乾淨。904 → 905 單元(靜態契約守衛);Playwright 60 → 61(Tab 遍歷)。(M-1)
[1.58.8] — 2026-05-20
feat(health): 在 #/health 顯示 OPENAI_API_KEY / QWEN_API_KEY / OPENROUTER_API_KEY(與 GEMINI_API_KEY 類似)。 v1.57.0 加入 OpenRouter 為第 5 個 headless live-eval 供應商;v1.55.3(UX-2)上線 4 供應商引導。但 #/health 頁僅顯示 GEMINI_API_KEY 與 ANTHROPIC_API_KEY — 其餘三個雖然 /api/status/providers 已路由,在 Health 卻不可見。使用者要求:將「set / unset (manual mode)」列模式擴充到所有 headless 供應商。server/lib/routes/health.mjs 新增 3 個可選檢查列,接入與 /api/status/providers 相同的 isUsableKey 閘。Health 視圖逐項處理 body.checks,因此無需新增 8 語言字串。903 → 904 單元。(使用者請求)
[1.58.7] — 2026-05-20
fix(security): NEW-2 — isValidJobUrl 現在拒絕成對的模板佔位符語法(${…}、{{…}}),與錯誤訊息一致。 POST /api/pipeline 的 400 回應聲稱 「contain no script or template characters」,但 v1.58.3 MASTER 回歸確認:實際僅 ASP/EJS 形式的 <%…%> 被 [<>"'\\s]守衛順帶攔截。JS 模板字面值${TEST}與 Mustache/Handlebars{{TEST}}直接通過 — 正則與錯誤訊息的語意不一致。fix-prompt 選項 A(將正則收緊以匹配訊息):在 [server/lib/security.mjs](https://github.com/Fighter90/career-ops-ui/blob/main/server/lib/security.mjs) 新增TEMPLATE_PATTERNS陣列,經hasTemplatePlaceholder(url)在new URL(…) 前檢查。**僅拒絕成對** 的佔位符({normal}` 等單括號 ATS 路徑繼續接受)。901 → 903 單元。(NEW-2)
[1.58.6] — 2026-05-20
fix(a11y/i18n): BUG-008-tb — 頂列 Doctor 模態框標題現在與本地化按鈕標籤一致。 v1.58.0 已關閉的台帳 BUG-008(「模態框標題 == 本地化按鈕標籤」)只涵蓋了 Health 頁面入口。v1.58.3 MASTER 回歸發現頂列入口仍違反不變量:無論 UI 語言為何,點擊頂列 Doctor 開啟的模態框標題始終為 doctor(小寫英文)。修正:public/js/app.js:118 將字面值 'doctor' 替換為 I18n.t('top.doctor', 'Doctor')。top.doctor 鍵在 8 種語言中皆已存在(EN Doctor · ES/pt-BR Diagnóstico · KO 진단 · JA 診断 · RU Диагностика · zh-CN 诊断 · zh-TW 診斷),與按鈕透過 data-i18n="top.doctor" 宣告的鍵相同。tests/qa-report-fixes.test.mjs 新增靜態契約守衛。900 → 901 單元;Playwright 60/60。(BUG-008-tb)
[1.58.5] — 2026-05-20
fix(ui): NEW-3 — #/followup Run-live 雙重 POST 判定為 無法重現;以 Playwright 回歸守衛鎖定。 v1.58.3 MASTER 回歸透過 monkey-patched window.fetch 觀察到:在 #/followup 上單擊 Run live 一次(公司/角色/備註已填、日期故意留空)後,~2 秒內出現兩次對 /api/mode/followup 的相同 POST。依 fix-prompt 的「先重現」原則,對 public/js/views/mode-page.js::submit() 做了原始碼審查:(a) Run live 與 Generate prompt 均為普通 <button>,各自只有單一 onClick,既沒有父 <form> 也沒有 addEventListener('submit'),因此不存在雙重觸發路徑;(b) UI.withSpinner()(FIX-L1)在請求進行中將 button.disabled = true,從源頭阻斷第二次物理點擊。在 tests/playwright-smoke.mjs 新增還原回歸劇本的測試 — 填入公司/角色/備註、留空日期、點擊與 Run live 共用 submit() 的手動按鈕,於 3 秒視窗內斷言 POST /api/mode/followup 恰好 1 次。選擇器與語言無關(8 種語言中 ▶ 字形相同),並透過 addInitScript 預先寫入 career-ops-ui:lang=en,避免同一瀏覽器內前一個語言切換測試影響欄位選擇器。Playwright 59 → 60。原 QA 觀察以劇本形式存檔,無需產品程式碼修改。(NEW-3)
[1.58.4] — 2026-05-19
fix(security): NEW-1 — 在每個回應上發送 Content-Security-Policy(此前僅在非 loopback 綁定時發送)。 在 v1.58.4 之前,僅當 isPubliclyExposed() 為真(HOST 綁定至 loopback 之外)時才附加 CSP 標頭;在 127.0.0.1 上,/ 與 /api/health 皆無 CSP 回應,UI.md() 的 escape-first 契約成為唯一的 XSS 防線。v1.58.3 MASTER 回歸(§5)將其標記為 stop-ship 不變量。現在 CSP 為無條件,無論綁定位址為何,在每個回應上皆相同:default-src 'self'; script-src 'self'; style-src 'self' https://fonts.googleapis.com 'unsafe-inline'; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; form-action 'self'。script-src 絕不允許 'unsafe-inline'/'unsafe-eval'。指令集相對此前的「僅對外暴露」策略未變(已適配 SPA — 為 Inter 將 Google Fonts 加入允許清單),無視覺或功能回歸。tests/security-headers.test.mjs 已重寫;Playwright 路由巡檢(en/ru/ja/zh-TW × 7 條路由)驗證 0 次 CSP 違規。900 單元 · Playwright 58→59 · e2e 20/20+23/23。後續 fix-prompt 項目依專案原則作為後續 one-fix 版本發佈。(NEW-1)
[1.58.3] — 2026-05-19
fix(deep):R-2 / FIX-C1 — 從研究輸出剝除孤立/不平衡的代理鷹架標籤。 v1.58.0 的 cleanLlmMarkdown 僅移除成對區塊與末尾開標籤。v1.58.2 深度回歸發現某模型產生不平衡軌跡——無開標籤的孤立 </tool_response>(及 </thinking>)殘留並字面渲染進已儲存的 #/deep 簡報。最終保守掃描現移除任何單獨鷹架標記(開/閉、平衡與否)、Anthropic 工具 XML(<invoke>/<parameter>/antml:*)與 tool_* 圍欄。純函式·冪等;真實 <https://…> 自動連結與程式碼保留。FIX-C2 三聯判定不可重現(i18n.js 已設 <html lang> 並偵測 navigator.language)。二者皆加回歸守衛。896 → 900 單元 · Playwright 58/58。v1.58.3 fix-prompt 其餘項按單修發布排隊(不批次)。
[1.58.2] — 2026-05-19
fix(i18n):I18N-011 — 在 7 個非 EN 語言中在地化 #/help 目錄。 TOC 由 docs/help/<lang>.md 的 ## 標題生成。第 3/4/6/7/8/9/10/11/12 節在 es/pt-BR/ko/ja/ru/zh-CN/zh-TW 仍是英文標題,導致側欄已翻譯而 TOC 仍英文。現將每個標題在地化為與側欄 nav.* 鍵完全相同的術語(單一事實源 — TOC 與側欄一致),保留節號與 (#/route …) 原文。EN 不變。關閉 v1.58 QA 唯一的 i18n 待辦。僅文件;896/896 單元 · 33/33 help · Playwright 58/58。
[1.58.1] — 2026-05-19
fix(test):CI 隔離的 checkProfileCustomized 守衛(v1.58.0 修補)。 v1.58.0 通過了(建議性)pre-commit 但在 ci.yml(Node 18/20/22)失敗:測試使用 cache-bust 動態 import + 改寫 PATHS,但 paths.mjs 每行程只解析一次專案根。改為健全的靜態守衛(allow-list + ^(…)$/i 錨定正則;含 “test” 的真實姓名絕不誤判)。無生產程式碼改動;同時解除 publish-package.yml。896/896 單元 · Playwright 58/58。見 qa/v158-regression/。
[1.58.0] — 2026-05-19
fix(qa):外部 QA 報告 bug 清掃 + 整潔、格式化的研究輸出。 修復:BUG-001 #/followup 在用戶端依 ISO YYYY-MM-DD 驗證可選日期;BUG-003 區塊引用內的 **粗體**/`程式碼`/連結現已渲染(所有說明頁);BUG-005 重複 URL 顯示「已在佇列中 — 已略過」;BUG-006 無效 URL 文案人性化((POST /api/pipeline · HTTP 400) 脈絡按設計保留);BUG-007/008「Running doctor.mjs…」toast 在彈窗前關閉(新增 UI.dismissToast()),彈窗標題=按鈕本地化文案;BUG-010 #/reports 空狀態補副標題;BUG-002/UX-032 checkProfileCustomized() 將測試夾具名判為「未自訂」(不動父專案 profile.yml/cv.md — 規則 #1);I18N-012/013 俄語 Deep research 真正翻譯。新增: cleanLlmMarkdown() 從 #/deep 與已儲存研究中剝除代理鷹架(<tool_call>{…}</tool_call>、<tool_response>、<thinking> …),涵蓋所有提供方及已儲存檔案讀取;#/outreach→#/contacto 別名(BUG-004);用戶端網路錯誤經 I18n.t() 本地化(8 語言;伺服器 details 按設計為英文診斷)。測試: 新增 tests/qa-report-fixes.test.mjs(10)、tests/llm-output.test.mjs(5),881 → 896 單元,Playwright 58/58。未改(含理由): BUG-009(#/cv H1 按設計,WCAG single-h1)、父資料(parent-owned)、minor i18n/UX 長尾列入待辦。完整細節見 CHANGELOG.md。
[1.57.2] — 2026-05-19
fix(config):/#/config「validation failed」的真正根因 —— SPA 注入的 lang 欄位。 public/js/api.js 會給每個 JSON POST 內文自動附加 lang(讓 LLM 路由取得 UI 語言)。/api/config 不是 LLM 路由,lang 也不是設定鍵,因此 validateConfig 的(正確且與安全相關的)未知鍵拒絕對每次儲存回傳 400:validation failed — lang: not a known config key。這只在瀏覽器出現:curl/行程內重現從不送 lang,所以 v1.57.0/.1 改善了訊息卻未除根因。設定路由現在在驗證前剝除傳輸用的 lang;KNOWN_KEYS 寫入過濾仍丟棄任何真正未知的鍵 —— 注入防護不變。由點擊真實儲存按鈕的新 Playwright 表單巡檢發現。測試: 新增 tests/playwright-forms.mjs(26,納入 npm run test:e2e:browser)巡檢所有表單;config-endpoint 增加瀏覽器等價用例。879 → 881 單元,Playwright 32 → 58。完整細節見 CHANGELOG.md。
[1.57.1] — 2026-05-19
fix(ux):每個 API 錯誤現在都說明「什麼失敗、在哪裡、為什麼」;輸入錯誤文案盡可能詳盡。 伺服器早已回傳 { error, details: ["欄位: 原因", …] },但各表單只顯示首行(「validation failed」),因此在 /#/config(及各處)無法得知哪個欄位有誤。api.js 現在全站將逐欄位 details 併入訊息(改一處,所有表單受益),附加請求上下文 (方法 /路徑 · HTTP NNN)(在哪裡),非 JSON 回應顯示原始內文片段,網路錯誤也帶方法+路徑;並暴露 err.details。validateConfig 訊息改為盡可能詳盡(哪裡錯、如何修)。密鑰欄位絕不回顯輸入值(僅字元數)——輸錯的真實 key 不會洩漏到 toast/日誌。PORT 範圍現真正驗證(99999 被拒)。/#/config 的 PORT/HOST 預填真實預設值(4317 / 127.0.0.1)。錯誤 toast 停留更久(9–20 秒)且換行/捲動而非截斷。測試: 新增 tests/config-validation-detail.test.mjs(12),874 → 879。完整細節見 CHANGELOG.md。
[1.57.0] — 2026-05-19
feat(provider): OpenRouter 作為第 5 個無頭即時評估提供方 + fix(config): 儲存任意 API key 時出現「validation failed」的修復。 貼上的 key 常帶有尾端換行或空白(作業系統剪貼簿、提供方主控台的「複製」按鈕)——1.57 之前這會觸發 所有 提供方的換行守衛,且以 $ 結尾錨定的 ANTHROPIC_API_KEY 正則會誤拒真實的 Anthropic key。現在 validateConfig 在驗證 之前 正規化(trim)每個值,路由持久化已修剪的值(執行期認證成功,不會因 \n 破壞 .env),Anthropic 檢查改為健全的 sk-ant- 前綴 + 長度(共用的 isUsableKey() ≥ 20 字元仍是真正的「是否真實 key」門檻)。內部換行仍被拒絕(.env 注入守衛)。OpenRouter 現為一等提供方:/#/config 的 OPENROUTER_API_KEY 一個 key 即可接入 300+ 模型。它是 auto 順序的最後一位(Anthropic → Gemini → OpenAI → Qwen → OpenRouter),因此既有設定絕不會被靜默改道;LLM_PROVIDER=openrouter 可固定。透過與 OpenAI/Qwen 相同的 _tailProvider() 路徑接入 /api/evaluate、/api/deep、/api/mode/:slug,並在 /api/status/providers 與 Health 儀表板中呈現。OpenAI 相容用戶端(無新相依——直接 fetch、AbortController 逾時、key 不記錄),帶建議的 HTTP-Referer/X-Title 標頭。模型下拉是即時的:OPENROUTER_MODEL 由 GET /api/openrouter/models(OpenRouter 公開目錄的伺服器端代理——保持 CSP connect-src 'self')填充,目錄不可用時回退精選清單,10 分鐘記憶體快取。8 種語言新增 i18n key(config.openrouter*)。測試: 新增 tests/openrouter-route.test.mjs、tests/openrouter-model-selector.test.mjs,擴充 env-config/openai/provider-selector。831 → 855。完整細節見 CHANGELOG.md。
[1.56.4] — 2026-05-19
feat(ui):UX-N2 — 全域搜尋輸入框上隨平台變化的可見 ⌘K / Ctrl K 提示。 Cmd/Ctrl+K(聚焦搜尋)快捷鍵此前只存在於 aria-label/原始碼,視力使用者無從發現,應用顯得比實際慢。現在搜尋膠囊末端出現一個低調的 <kbd class="kbd-shortcut">,啟動時依平台判定(navigator.platform/userAgent)從 data-mac/data-other 填入:macOS/iOS 為 ⌘K,其餘為 Ctrl K。它 aria-hidden="true"(既有 aria-label 已向輔助技術播報——徽章不應重複)且 pointer-events:none(裝飾)。既有 Cmd/Ctrl+K 綁定不變。無新增 i18n 鍵(字形通用);徽章是既有 .searchbar 的 flex 子元素(無需包裹/絕對定位——input 已 flex:1)。測試: 新增 CI 隔離原始碼靜態套件 tests/cmdk-hint-visible.test.mjs(5):<kbd class="kbd-shortcut"> 位於 .searchbar 內;aria-hidden="true" 且含 data-mac/data-other 兩個變體;app.js 經 navigator 判定填入;(e.ctrlKey||e.metaKey)&&e.key==='k' → search.focus() 綁定健在(回歸保護);app.css 為 .kbd-shortcut 設樣式且非 display:none。826 → 831。feat(ui) · test: tests/cmdk-hint-visible.test.mjs。詳情見 CHANGELOG.md。
career-ops-ui v1.267.1 · page 6/9 · mirror of the project changelog for cvstart.org