変更履歴

GitHub

すべての注目すべき変更をリリースごとに記録しています。同じファイルがリポジトリに収録されており、17言語すべてに翻訳されています。

変更履歴

career-ops-ui の主要な変更履歴。形式は Keep a Changelog、バージョンは SemVer に準拠します。

翻訳: 🇬🇧 English · 🇪🇸 Español · 🇧🇷 Português · 🇰🇷 한국어 · 🇷🇺 Русский · 🇨🇳 简体中文 · 🇹🇼 繁體中文 · 🇫🇷 Français · 🇵🇱 Polski · 🇺🇦 Українська · 🇩🇰 Dansk · 🇸🇦 العربية · 🇩🇪 Deutsch · 🇮🇹 Italiano · 🇹🇷 Türkçe · 🇮🇳 हिन्दी

翻訳ノート — このファイルは全エントリが日本語本文で完全に翻訳済みです。コードブロック、コミットメッセージ、ファイルパス、URL、環境変数、コマンド、リンクラベルは原文のまま保持しています。


[1.134.1] — 2026-08-05

検証の堅牢化 — プロジェクト全体の監査で見つかった修正です。

修正

  • successfactors がスキャン中の失敗で収集済みの求人を破棄しなくなりました(v1.134.0 のデッドボード例外化の移植で生じた回帰)— ページネーションループに try/catch がなく、2ページ目以降(1ページ目は成功済み)での失敗が例外を投げてしまい、すでに収集済みのものすべてが失われていました。さらに、その失敗が 404(範囲外の startrow による)だった場合、en-scanner は稼働中のテナントを何日も停止扱いとして隔離してしまっていました。今後は phenom/radancy と同様の挙動になります。0ページ目での失敗は今も例外を投げます(ボード停止)が、それ以降のページでの失敗は部分結果を保持します。
  • #/scan のフィルターチップがキーボードで操作できるようになりました(WCAG 2.1.1)— ファセットチップ(および「クリア」チップ)はクリックハンドラーを持つ span 要素でしたが、tabindex や role がなく、キーボードユーザーやスクリーンリーダーユーザーが到達・切り替えできませんでした。現在は role="button"tabindex="0"aria-pressed を備え、Enter/Space キーでも操作できます。
  • 3つのハードコードされた英語文字列がローカライズされました#/scan の信頼バッジのツールチップ、#/scan の移転列ヘッダー、#/dashboard のスコア列ヘッダーは、キーとして存在しない裸のリテラルだったため i18n パリティゲートから見えず、英語以外のすべてのロケールで英語のまま残っていました。現在は scan.trustTip + scan.col.reloc(新規2キー)と、既存の track.col.score の再利用になり、ソース静的ガード(tests/scan-chip-a11y.test.mjs)で固定されています。
  • +3 テスト → スイート 2187

[1.134.0] — 2026-08-05

親 career-ops v1.25.0 パリティ。

追加

  • 新しいスキャンソース: getManfred(manfred)— 給与が公開されているスペイン/EU圏のテック職を横断的に集めるボード全体フィードで、www.getmanfred.com/api/v2/public/offers から取得します(認証不要、ホスト固定 + HTTPS 限定、単一リクエストで全カタログを取得)。ソース + アダプター + CI 分離型のテストスイート(tests/sources-manfred.test.mjs)を追加。レジストリは 73 ソース = 68 EN + 5 RU(ALL_ADAPTERS 68)になりました。#/scan の Source フィルターと cvstart.org のランディングページに表示されます。

修正

  • a16z Speedrun フィードが50件で静かに打ち切られていた問題(#2404)— このフィードは1ページあたり50件が上限ですが、ソース側は PER_PAGE = 100 を要求していたため、1ページ目でページネーションが停止していました。50に修正しました。
  • 稼働していないボードが「稼働しているが空」として読み取られる問題を修正(#2379)— cryptocurrencyjobsphenomradancysuccessfactors:リクエストが一件も解決しなかったフェッチ失敗はこれまで空のリストとして飲み込まれていましたが、今後は例外を投げるようになり(#/portals のヘルスチェックとスキャンが実際の失敗として記録します)、1件以上成功した後のスキャン途中の失敗は部分結果を保持します。
  • workable が公開ウィジェットAPIを使うようになりました(#5ab8425)— apply.workable.com/api/v1/widget/accounts/<slug> に切り替えたことで、大規模アカウントの求人一覧を1リクエストで全件取得できるようになり、大規模アカウントが打ち切られなくなりました。

補足

  • 未移植(CLI専用、または web-ui にミラーされていないもの):detect-reposts の #2389 タイトルバケット化によるパフォーマンス改善;Unicode 対応の会社キー修正(web-ui 独自のトラッカー重複排除はすでに非ラテン文字に対応済みのため不要);scan --since;cv-facts;CV テンプレート/PDF 監査パス;doctor;モードの信頼できないコンテンツディレクティブ。

[1.133.1] — 2026-08-02

修正

  • #/funded(資金調達企業)が結果を表示するようになりました — 二つのバグにより、親の company-funded.mjs が完全な一覧を返しているときでも、テーブルには常に「資金調達企業なし」と表示されていました。(1) ビューは結果を res.candidates から読み取っていましたが、親は companies の下にそれらを送出します(各項目は { company, amount, round, funding: { sources: [{ source, url, observed_date }] } } という形です)。クライアントは正しいキーを読み取り、実際のエビデンス形状にマッピングするようになりました。(2) 結果テーブルはセルを可変長引数として UI.el('tr', {}, …) に渡していましたが、UI.el(tag, attrs, children)children を単一ノードまたは配列として受け取るため、最初の列(Company)しか描画されていませんでした — セルは配列として渡されるようになりました。実機ブラウザで検証済みです:4つのフィード全体で11社が Company / Funding signal / Source / Date の各列とともに描画され、エビデンスリンクも機能し、コンソールエラーはゼロです。結果が空のときも、ソースごとの診断情報が表示されるようになったため、静かなニュースの日とブロックされたフィードとを見分けられるようになりました。
  • tests/parity-routes-v1133.test.mjs にリグレッションガードを追加しました:偽の親スクリプトが実際の companies 出力形状を送出するようになりました(元のフィクスチャは誤った candidates 形状を反映しており、これこそがこのバグがグリーンのまま出荷された理由です)。加えて、funded.jsres.companies を読み取り(res.candidates は決して読み取らない)、テーブル行を配列の children で構築していることを検証するソース静的カナリアも追加しました(+1 → 2144)。

[1.133.0] — 2026-08-01

追加

  • 資金調達企業ディスカバリー(#/funded、親パリティ #2117) — 親 career-ops の company-funded.mjsGET /api/company-funded 経由でリレーする新しい読み取り専用ビューです。公開されホスト固定された資金調達フィード(TechCrunch、PR Newswire、The Guardian、Hacker News)から発見された、最近資金調達を行った企業のレビューファーストな一覧を表示します。このリレーはスクリプトを --json --dry-run で実行し(JSON を標準出力へ、ファイル書き込みなし)、ユーザー入力を --sources へ決して引き渡さず、レートリミットを備え、ユーザートリガー式です(マウント時ではなく Discover ボタンによって起動)。新しいルートモジュール server/lib/routes/funded.mjs + public/js/views/funded.js が Sourcing 配下に追加されました。
  • 週次面接ダイジェスト(#/interview-digest、親パリティ #2129/#2130) — 親のゼロ LLM weekly-digest.mjsGET /api/interview/weekly-digest 経由でリレーする新しい読み取り専用ビューです。面接セッションのメモを機械的に集約し、今週どの企業・どのラウンドで面接を行ったか、繰り返し登場するコンピテンシー、ベストエフォートで抽出した未解決のギャップを示します。オプションの ?from=&to= 範囲は両方とも有効な YYYY-MM-DD の場合にのみ引き渡され、範囲が空でも有効な available:true ダイジェストになります。server/lib/routes/interview.mjs + public/js/views/interview-digest.js に追加され、Analytics 配下に置かれます。
  • 両リレーとも、親スクリプトが存在しない場合(CI、スタンドアロンインストール)には既存の fail-soft な available:false コントラクトに従います。新規 i18n キー 26 個 ×17 ロケール、CI 分離型スイート tests/parity-routes-v1133.test.mjs(+5 → 2143)。

補足

  • 親 career-ops は v1.24.0 以降、Next.js の web/ アプリに Follow-up Tracker ページ(#1422)とバックエンド PDF レンダリング(#2182)を追加しましたが、これらは移植していません — web-ui にはすでに独自のフォローアップリレーと PDF ランナーがあり、基盤となる followup-cadence.mjs の堅牢化はシェルアウトリレー経由で自動的に取り込まれます。set-status.mjs / tracker-utils.mjs の変更は CLI 内部のものであり、ミラーしません。

[1.132.0] — 2026-07-31

変更

  • #/scan の結果描画サブシステムを public/js/lib/scan-results.js に抽出(ファイルサイズ規約の負債解消 — public/js/views/scan.js は約1254 LOCまで肥大化していました)。renderResultsbuildChipRow、行/ファセットビルダー群、オプションペインター群、FALLBACK_SOURCES レジストリのミラーからなるこのサブシステムは、ビュー側が渡すコンテキストオブジェクトをクロージャで保持する window.ScanResults.create(ctx) ファクトリへ移動しました。挙動の変更は一切ありません — 各関数はそのまま移動し、クロージャ変数を ctx.* に付け替えただけです。scan.js は現在約906 LOCです(800-LOC目標に向けた2回目の抽出パスを予定)。
  • 新しいブラウザ内リグレッションゲートtests/playwright-scan-filters.mjs が既定の data/last-scan.json をシードし、#/scan の全フィルターを駆動して行数を厳密に検証するため、この抽出は実ブラウザの挙動に対して検証されています。
  • README バナーをスリム化 — バージョンごとの長大な「最新リリース」ナラティブの壁を廃止し、1行の要約 + 完全な変更履歴(本ファイル)へのリンクに置き換えました。

[1.131.2] — 2026-07-31

変更

  • app.css を3つの順序付きスタイルシートに分割(ファイルサイズ規約の負債解消 — 単一ファイルが約1990 LOCまで肥大化しており、800-LOCのハード目標を大きく超えていました)。現在は app.css(約672 LOC — アクセシビリティ、デザイントークン/テーマ、サイドバー、メイン、ボタン、コンテンツシェル)、components.css(約595 LOC — カード、グリッド、ページネーター、バッジ、テーブル、フォーム、ログ/コンソール、Markdown、言語スイッチャー、チップフィルター、接続バナー)、overlays.css(約737 LOC — トースト、通知ドロワー、モーダル、その他/レスポンシブ、[dir="rtl"] ミラー、docs-fab、usage-hud)の3つとなり、いずれもハード上限に収まっています。
    • 分割は連続的かつ順序どおりに行われているため、カスケードは分割前のファイルとバイト単位で完全に同一です。index.html はこの3つを順序どおりの <link> として読み込みます。挙動・マークアップ・i18nの変更は一切ありません。
    • CSSを検証するテストは、共有ヘルパー tests/helpers/css.mjs::loadAppCss() 経由で連結結果を読み込むようになりました。新規の tests/css-modularization.test.mjs が分割を固定します(ファイルの存在・各ファイルが800 LOC以下であること・index.html のリンク順序) → スイート 2138。ブラウザ上での検証も実施済みです: 3つのスタイルシートすべてが正しくパースされ、そのルールが適用されます。

[1.131.1] — 2026-07-31

修正

  • v1.130.0 の2つのソースにおけるアダプターのホスト固定の一貫性強化(コードレビュー対応、多層防御。有効な入力に対する挙動変更はありません):
    • a16z-speedrun-talent アダプターapi: / a16z-speedrun-talent: のオーバーライドを buildEndpoint で再検証するようになりました(HTTPS 限定、厳密なホスト speedrun-talent-network.com)。検証に失敗した場合は正規フィードへフォールバックします — cryptocurrencyjobs アダプターとのパリティであり、ホスト外の値がフェッチ処理に到達することはもうありません(以前はフェッチ時点の assertSpeedrunUrl ガードのみに依存していました)。厳密ホストチェックは、ガードとアダプターで共有される単一のエクスポート済み SPEEDRUN_TALENT_HOST_RE になりました。
    • cryptocurrencyjobs パーサーcleanUrlassertCryptocurrencyJobsUrl およびアダプターのオーバーライドと同じ厳密一致のホストガードを使うようになりました(以前は endsWith で、サブドメインも許容していました)。パーサーが SSRF ガードより緩くなることはありません:sub.cryptocurrencyjobs.co のアイテムリンクは破棄されます。
    • +2 テスト → スイート 2135

[1.131.0] — 2026-07-31

追加

  • #/tracker の CRM ステージタブボード(親 Web アプリの /pipeline ビューを移植)。トラッカーのファネルチップバー+ステータスドロップダウンがステージタブ帯に置き換わりました。All タブに加え正規ステータスごとに 1 つずつのタブ — Evaluated · Applied · Responded · Interview · Offer · Rejected · Discarded · SKIP · Hired — が並び、それぞれ全履歴のライブ件数を表示します。ゼロ件のステージも含むため、ファネル全体が常に見渡せます(CRM らしい見た目)。アクティブなタブがフィルタを駆動し、同じタブを再度クリックすると All に戻ります。行はスコアトーン・正当性・PDF・レポートの操作性をそのまま保持し、ロゴを有効にすると企業セルにブランドロゴが表示されるようになりました(デフォルトはオフ → 追加リクエストはゼロ)。
    • 新しい読み取り専用ルート GET /api/tracker/stages が、正規のファネル(順序付きラベル)+エイリアス畳み込みマップを返します。ソースは server/lib/states.mjs(templates/states.yml、組み込みフォールバック付き)— これによりクライアントはステータスのホワイトリストを一切ハードコードしません。パラメータなしの従来の GET /api/tracker レスポンスは変更なし({ rows } のみ)。
    • 新しい純粋関数でユニットテスト済みのクライアントライブラリ public/js/lib/tracker-stages.js が、行をサーバーのステージに振り分けます。余分な markdown 太字やローカライズ済みエイリアス(例:aplicadoApplied)も許容します。タブはアクセシブルです(role tablist/tab、aria-selected、44px 以上のヒット領域、各タブのアクセシブルネームに件数を含む)。新規 i18n キーなし。スイート 2133

[1.130.0] — 2026-07-31

追加

  • 親 career-ops v1.24.0 から新スキャンソース2件を移植(インプロセス、新規依存なし;いずれも #/scan の Source フィルターと cvstart.org のランディングページに表示されます):
    • a16z Speedrun(a16z-speedrun-talent、#2231)— a16z Speedrun の タレントネットワーク ボード全体 JSON フィード。speedrun-talent-network.com にホスト固定、HTTPS 限定、0 始まりのページネーション(上限あり)、企業別の q/設定引き回し、fail-soft。
    • Cryptocurrency Jobs(cryptocurrencyjobs)— Web3 求人ボード cryptocurrencyjobs.co を、公開 RSS 2.0 フィード経由で取り込み(認証不要)。二段階の XML エンティティデコード、リモート限定の求人、タイトル末尾の "… at <Company>" から雇用主を抽出。
    • レジストリ合計は 72 ソース(67 EN + 5 RU) になりました(ALL_ADAPTERS = 英語圏ポータルアダプタ 67 件)。

修正

  • echojobs — ハイブリッド勤務がリモートと区別されるように(親 #2258 に準拠)。大文字小文字を区別しない hybrid マーカーが検出されると、Remote に丸め込まれる代わりに "<City> · Hybrid"(都市名がない場合は単に Hybrid)と workplaceType: 'Hybrid' を返すようになりました。
  • radancy — レガシー TalentBrew マークアップ + JSON 結果フラグメント転送(親 a3e6df9 に準拠)、注入可能な opts.fetchJson でゲート。

補足

  • 未移植 — CLI 専用の親機能。 career-ops v1.24.0 の大規模な CLI/モード面は web-ui の対象外のままです。web-ui はビューア+薄い書き込みスルーであり、モードホストではありません:コンプライアンス/管轄区域テーブル、連絡先電話帳 + vCard、面接トランスクリプトのデブリーフ/通話プラットフォーム検出、台帳の set-status、結果記録、二段階トリアージ、jd-similarity、バージョン管理された応募先 CV アーティファクトのスキーマ、doctor の Playwright-MCP 検出、portals/fix-slugs.mjs。親の scan.mjs にあるスキャンオーケストレーションの変更 — Interamt.de の Playwright スキャナー、iCIMS リバース ATS のフルスイープ、国籍適格性によるリモートフィルター、DNS ルックアップのペーシング、StepStone の rltr 重複排除、スキャン履歴の正規化された会社カラム — も対象外です:web-ui は EN/RU スキャナーをインプロセスで実行しており、scan.mjs へシェルアウトしません。
  • すでに対応済み。 role-matcher のアクセント畳み込み修正(#2209)は v1.127.0 で移植済みのため、ここでは no-op です。

[1.129.1] — 2026-07-29

修正

  • v1.128/v1.129 の web 移植への AI レビュー対応(すべて助言、根本修正):job-facets.js のレベル優先順位(明示的な修飾語がマネジメント語に勝つ — Senior Engineering Managersenior、以前は lead);states.mjs のフォールバックがピン留めされなくなった(成功読み取りはメモ化、フォールバックはキャッシュせず返す — 起動時に一時的に不在の親は次回再読込)+ 存在するが不正なファイルで console.warn;score-tone.js — スコアなしの行は中立(muted)で赤ではない;domainFromName()/api/logo の前に非 ASCII スラッグをスキップ;+tests/states.test.mjs の分離ガード。+4 テスト → 2073

[1.129.0] — 2026-07-29

追加

  • #/scan レベルファセット + 経過カラム — v1.128.0 の job-facets.js ライブラリがスキャン UI に接続されました(以前はロジックのみ)。新しい レベル ドロップダウンが各求人タイトルを lead/staff/senior/mid/junior/intern に分類(JobFacets.seniorityFromTitle)し、結果に実在するものから自動生成します(Country ファセットと同様);レベル語のないタイトルは常に通過。保存検索・リセット・適用に保持されます。結果テーブルに レベル バッジ列と無トークンの 経過 列(今日/N日JobFacets.daysSince)が追加されます。i18n キー 12 個 ×17、+3 テスト → 2069

[1.128.0] — 2026-07-29

追加

  • 親プロジェクト自身の Web アプリ(../web/, Next.js)から 4 つの解決策を移植 — バニラ JS/ESM で再実装、新規依存なし:(1)server/lib/states.mjstemplates/states.yml をトラッカーのステータス語彙の唯一の情報源としてライブ読み取り(CI フォールバック付き)— 毎リリースの手動ホワイトリスト再同期を廃止;POST はエイリアス(スペイン語/レガシー)を正規ラベルへ畳み込み、GET のファネルは正規ステータスでバケット;(2)ATS ホスト行の会社ロゴ — domainFromName()(約 90 ブランド→ドメイン);(3)score-tone.js — 4 段階スコアトーン(≥4.2/3.8/3.0 + 文字フォールバック);(4)job-facets.js — seniority/source/days ファセット。+21 テスト。

補足

  • 未移植(概念のみ):親のエージェント的アクション層(actions/registry.ts + api/assistant/route.ts)— docs-fab をコパイロット化する際の設計図。新規ソースなし(レジストリ 70)、i18n/help 変更なし。

[1.127.0] — 2026-07-29

追加

  • 3 つの新スキャンソース(career-ops v1.23.0 パリティ) — レジストリは 70 アダプター(65 EN + 5 RU) に: Flowxtra(無認証の全体アグリゲーター)、VDAB(フランダース公共雇用サービスのキーワード API)、iCIMS(careers-<tenant>.icims.com ポータル、jibeapply とは別)。さらに Cursor が CLI ロスターに復帰(parent #2115): cli-detectcursor も検出(10 ツール)し、help/README/config ×17 にロスターを復元。

修正

  • agenticjobs を HTML スクレイピングから REST API へ(#2167);Greenhouselocation.name が勤務形態のみのとき /offices から都市を復元(#2104);role-matcher パリティ(#1933/#2164/#2009: MTS 接頭辞、product ベースライン、アクセント畳み込み、サブベースライン不一致)。

補足

  • 未移植。 v1.23.0 の大半は web-ui が使わない CLI/ダッシュボード面(batch-tailor、discover-ats、NL/PT モード、PDF テーマ、Go ダッシュボード、updater/doctor);リレースクリプトは変更不要。親 VERSION → 1.23.0

[1.126.1] — 2026-07-25

修正

  • v1.126.0 の再同期が見落とした CLI ロスターのドリフト 2 箇所 — (1) #/configAPI keys タブ導入文(config.providerModelNote、i18n ×17)が 7 CLI しか列挙していなかった — AntigravityGrok Build を OpenCode の後に挿入; (2) ヘルプガイド(×17)の 2 つ目の比較表の行と CI ビルドのサイト help がまだ Inside Claude Code / Codex / Cursor / Gemini CLI(旧 Cursor 入り)だった — 全ロスターに修正。どちらも v1.126.0 スイープのパターンが対象外だったスラッシュ/中黒区切り。i18n スナップショット再生成、スイートは 1969 維持。

[1.126.0] — 2026-07-25

追加

  • AI CLI ツールタブが career-ops の 8 つの一級 CLI をすべて検出#/config のロスターを親の docs/SUPPORTED_CLIS.md と同期: server/lib/routes/cli-detect.mjsGrok Build CLI(grok)と Kimi CLI(kimi)を追加し、Antigravity は正規バイナリ agy を優先的に探索します。読み取り専用の PATH スキャンは 9 ツール を報告するようになり、見つかったバイナリを実行しない点は変わりません。

変更

  • career-ops.org/docs とのドキュメント再同期 — すべてのドキュメント面を親のライブページ(全 31 ページを読了)と突き合わせました。正規の AI アシスタントロスター(help ×17 + README ×17)は、8 つの一級 CLI — Claude Code、Codex、OpenCode、Antigravity CLI、Grok Build CLI、Qwen Code、Kimi、GitHub Copilot CLI — と Gemini CLI(レガシーラッパー)を列挙します。ヘルプバンドルは 29 H2 / 105 H3 構造を維持します。

[1.125.4] — 2026-07-23

変更

  • site の依存関係(dependabot #151–#153)— site/sharp 0.34.5→0.35.3、svgo 4.0.1→4.0.2、fast-uri(dev)3.1.3→3.1.4。Astro ビルドはグリーン、SPA/サーバーへの影響なし。

補足

  • 親プロジェクトのパリティスイープ(career-ops 37d17ec..254764a、v1.22.0 以降) — 移植対象なし: set-status の誤行ガード(#2108)は CLI 専用(web-ui のトラッカー行は UI で明示的に選択され、どのルートも set-status.mjs を呼ばない)、ローカライズ済みモードの Risk Summary(#2109)は web-ui が読まない modes/<lang>/ ファイル(読むのはトップレベルの modes/*.md のみ)、update-system のマニフェスト検証(#2111)はアップデーター専用、残りは親のドキュメント(トルコ語 README、SIGNATURES ×4、SCRIPTS.md、es のアクセント)。親の VERSION は 1.22.0 のまま — parentVersion に変更なし。

[1.125.3] — 2026-07-23

修正

  • デンマーク語・ヒンディー語の LLM プロンプトが英語で応答していた問題(ユーザー報告)— server/lib/prompts.mjsLOCALE_NAMES と 5 つの SCAFFOLD_STRINGS ブロックが dahi に拡張されておらず、resolveLocale()en にフォールバックし、ディープリサーチ(ライブ・手動)、モード実行、評価、面接、ネットワーキング、CV Studio のすべての AI プロンプトから # Output language 指示が失われていました。両ロケールを正式サポート: ロケール指示 + ローカライズ済みスキャフォールディング。tests/locale-scaffold.test.mjs の回帰ゲートはハードコードされた 12 件ではなく正規の 17 ロケール一覧を走査し、新しい構造パリティゲートは英語にフォールバックするスキャフォールドキーを失敗させます — 今後 prompts.mjs を見落としたロケールは出荷できません(+12 テスト、スイートは 1969 件に)。

[1.125.2] — 2026-07-22

修正

  • Gemini でのディープリサーチ:HTTP 502(MALFORMED_FUNCTION_CALL) (#145、@Alien10140 の貢献) — ライブの /api/deep プロンプトはモデルに「Use WebFetch / WebSearch」とファイル保存を指示していましたが、ヘッドレス API プロバイダにはツールチャネルがなく、Gemini はテキストではなく関数呼び出しで応答し、空の HTTP 502 として現れていました。buildDeepPromptbundleProjectContextheadless フラグを追加:ライブ実行(Anthropic/Gemini/フォールバックカスケード)はインライン化されたコンテキストからブリーフを書くツールなしプロンプトを受け取り、Claude Code 用のコピー&ペーストプロンプトはツール指示を保持します。tests/critical-fixes.test.mjs にテスト +1。

変更

  • 非推奨の gemini-2.0-flash を超えて Gemini デフォルトを更新 (#144、@Alien10140 の貢献) — 設定ドロップダウン、gemini.mjs のサーバーフォールバック(ヒントと静かに食い違っていた値)、OpenRouter フォールバックチェーン、config.geminiModelHint ×17、ヘルプガイド ×17 がすべて gemini-3.6-flash を指すようになりました。新しいドリフトゲート tests/gemini-default-model.test.mjs(+5 テスト)がすべての面を同一リテラルに固定します — スイートは 1957 テストになりました。

[1.125.1] — 2026-07-21

修正

  • SuccessFactors:マルチブランドの RMK テナントがブランドパスを維持(親 #2099、v1.22.0 以降)— 一つの共有 RMK インスタンス上で複数の買収ブランドを運用するホールディングカンパニーは、パスセグメントでブランドを区別します(careers.nemetschek.com/Bluebeam/ vs …/Vectorworks/)。アダプタは以前、設定された URL を origin まで切り詰めてしまい、親ブランドの求人だけを黙ってスキャンしていました。エンドポイントは今やブランドプレフィックスを保持し、末尾の /search/ または /tile-search-results/ セグメントのみを取り除くため、二重スキャンが発生することはありません。単一ドメインのテナントはバイト単位で変更されません。新しくエクスポートされた resolveTenantBase ヘルパー + tests/sources-successfactors.test.mjs に移植したテストブロック 1 件。

[1.125.0] — 2026-07-21

追加

  • cvstart.org:「求人ソース」ランディングセクション — スクリーンショットと比較表の間に新しいセクションが追加され、67 件のスキャナーソースすべてをクリック可能なチップ(英語圏の求人ボード/ATS 62 件 + 独自の見出しの下にまとめたロシア語圏のボード 5 件)として一覧表示します。各チップはそのソースの公開サイトへリンクします。この一覧はビルド時に実際のアダプタレジストリ(sync-assets.mjsfacts.sources)から同期されるため、アプリの実態と乖離することはありません。Sources.astro 内の厳選されたリンクマップは、新設の tests/site-sources.test.mjs によって保証されます。ヘッダーナビゲーションに Sources アンカーが追加され、サイトの i18n キーが 4 件 × 17 言語分新設されました。あわせて、ランディングページの JSON-LD の inLanguage 一覧に hi が抜けていた問題も修正しました。

[1.124.0] — 2026-07-21

追加

  • 5 件のスキャンソース(親 v1.22.0 パリティ、#1808/#1572/#2024/#2055)— Welcome to the Jungle(ボード全体の JSON API)、Agentic Engineering Jobs(エージェンティック/AI エンジニアリング専門ボード)、Jobvite(ゼロ認証のテナント単位 ATS)、Gem(テナント単位 ATS)、Alibaba Group(キャリア JSON API、Meituan/Tencent パターン)。いずれもホスト固定・CI 分離されたソース + アダプタのペアで、レジストリは 67 個のアダプタ(英語圏 62 個 + ロシア系 5 個) を同梱するようになりました。#/scan の Source ドロップダウンのフォールバックとそのドリフトゲートも更新済みです。新しいテストスイート tests/sources-{wttj,agenticjobs,jobvite,gem,alibaba}.test.mjs を 5 本追加。

修正

  • Arbeitsagentur:全国リモート判定は homeofficetypVOLLSTAENDIG の場合のみ(親 #1981)— homeoffice=nv_true クエリはハイブリッド求人も返してしまうため、リモート判定は各ヒットを求人詳細エンドポイントに対して小さなバッチで確認するようになりました。照会がエラーになった場合はフェイルクローズし、求人の実際の勤務都市を保持するため、勤務地フィルタは引き続き適用されます。
  • SmartRecruiters:公開求人 URL に /postings/ が付与されずに生成される問題(親 #2047)— リンクは、公開サイトがこのセグメントを省略しているテナントで 404 になる代わりに、公開求人ページへ正しく到達するようになりました。

補足

  • 親 v1.22.0 では、Web UI がシェルアウトしていない、またはすでにカバーしている CLI 側の変更も出荷されています:zh-CN 向け CV テンプレート + PDF タイポグラフィ、/expand モード、プロバイダのプロンプトキャッシュ調整(Gemini/OpenAI/Ollama)、ステップ単位のトークン内訳(Web UI は独自の使用量メーターを保有)、トラッカーのライターロックによる直列化(Web UI は v1.21 以降 withFileLock で書き込みを経路化)、スキャンの visa_filter + 絶対投稿日 CLI フラグ(Web UI は独自の「投稿からの経過日数」フィルタを保有)、そして seen-sources 重複排除のシード投入(Web UI スキャナーは独自のスキャン履歴による重複排除を保持)です。

[1.123.0] — 2026-07-17

追加

  • Oracle Recruiting Cloud スキャンソース(親 v1.21.0 パリティ、#1929)— Oracle Fusion/ORC 系のキャリアサイト(JPMorgan Chase、Oracle、BNY Mellon、American Express、Honeywell など)が使うゼロ認証の recruitingCEJobRequisitions REST API:*.fa[.<region>][.ocs].oraclecloud.com にホスト固定し、サイト番号は各トラッキング対象企業の careers_url から解決、オフセットページネーションはハード上限付き、WAF を意識したブラウザ風ヘッダーを使用します。レジストリは 62 個のアダプタ(英語圏 57 個 + ロシア系 5 個) を同梱するようになりました。#/scan の Source ドロップダウンのフォールバックとそのドリフトゲートも更新済みです。CI 分離された新しいテストスイート tests/sources-oraclecloud.test.mjs を追加。

修正

  • repost 検出器:ベースタイトルを特化サフィックス違いの兄弟求人と区別(親 #1922)— 「Senior Analytics Engineer」が「Senior Analytics Engineer, People Analytics」とクラスタリングされなくなりました:一方のタイトルのトークンが他方の厳密な部分集合であり、余分なトークンが(基本語ではなく)実際の専門分化を示す場合、両者は別々に応募可能な求人として扱われます。再掲載の注記(「(Repost)」、「relisted」)はメタ的なノイズとしてストップワード化されました。tests/detect-reposts.test.mjs に +2 アサーション。

補足

  • 親 v1.21.0 では、Web UI がシェルアウトしていない、またはすでにカバーしている CLI 側の変更も出荷されています:同一企業への再応募警告(Web UI は v1.84.0 以降、再応募クールダウンを保有)、カバーレターの --format / --report フラグ、面接のレッドフラグ / パネルインテル / 無断欠席メールのプロンプトモード、スキャンの信頼シグナル & ポータルヘルスの永続化(Web UI は独自のインプロセススキャナーで trust-validator と Portals health ページを運用)、そして stats/salary-gap の拡張(読み取り専用かつフェイルソフトで中継)。

[1.122.0] — 2026-07-16

追加

  • ヒンディー語(हिन्दी)— 17番目の言語 — 完全な UI 辞書(約 1,110 キー)、完全なアプリ内ヘルプガイド(29 の H2 / 105 の H3 パリティ)、README.hi.md、新しい CHANGELOG.hi.md(de/it/tr の前例に倣い v1.122.0 から開始)、cvstart.org のランディング + メソドロジー/ライセンス/変更履歴/ヘルプページ、言語スイッチャー(🇮🇳)、ブラウザ言語の自動検出、ローカライズされたダッシュボードのスクリーンショットを追加しました。×16 のパリティゲートはすべて ×17 で実行されるようになりました:i18n 辞書パリティ + スナップショット、ヘルプ H2/H3 ゲート、変更履歴パリティ、サイトの check-i18n、そして Playwright のロケール一巡テストです。

[1.121.0] — 2026-07-16

追加

  • cvstart.org: メソドロジー、ライセンス、変更履歴ページ — ランディングに、既存の Compare ブロックの隣に全 16 言語で 3 つの新セクションが追加されました: /methodology/(6 次元の 0.0–5.0 スコアリングルーブリック、4.0 の応募しきい値、絶対にしないことのルール — career-ops.org/methodology のローカライズされた要約)、/license/(NOTICE.md へのリンク付きの正規 MIT 全文)、/changelog/(このファイルを、リポジトリの 16 の翻訳済み CHANGELOG からロケールごとにレンダリングしたもの)。ヘッダーに新しい Methodology エントリ、フッターの Resources にもリンクを追加。sync-assets.mjs はビルド時に CHANGELOG ×16 と LICENSE をサイトへ同期するようになり、ページがリポジトリから乖離することはなくなりました。
  • ドキュメント全体へのメソドロジーリンク — README(全 16)、アプリ内ヘルプガイド §1 の正規ガイドリスト(全 16)、そして wiki が、既存の career-ops.org/docs ガイドと並んで career-ops.org/methodology(FAQ・用語集にも)にリンクするようになりました。

変更

  • README のリリースバナーとバッジを更新(テスト 1850、リリース v1.121.0)— バナーはまだ v1.119.5 を告知したままでした。

[1.120.0] — 2026-07-16

追加

  • CareerOps マニフェスト(親 v1.20.0 パリティ)— 親プロジェクトが CareerOps マニフェスト(MANIFESTO.md · career-ops.org/manifesto)を公開し、README・アップデーター・Go ダッシュボードから案内するようになりました。Web UI もこれに追随します:サイドバーフッターの新しいリンクからマニフェストのページが開くようになり(全 16 ロケールに新しい i18n キー footer.manifesto を追加)、アプリ内ヘルプガイドには全 16 言語で §29「CareerOps マニフェスト」が追加され、README はマニフェストとは何か・どう署名するかを説明し、cvstart.org のランディングフッターにもリンクが張られました。

備考

  • 親 v1.20.0 では、upskill のターゲットモードにおける既知スキルの抑制も修正され、scan --json の標準出力がパース可能であり続けるよう dotenv を静音化し、役職見出しがその箇条書きから分離しないよう HTML CV テンプレートを修正しました — いずれも Web UI がシェル経由で呼び出さない CLI 側の挙動であり、Web UI 側のコード変更は不要でした。

[1.119.5] — 2026-07-13

修正

  • ランディングの言語ボタンが折り返さなくなりました — v1.119.2 の国旗追加により、ヘッダーのスイッチャーラベル(例:「🇷🇺 Русский」)が狭いデスクトップ幅で最大 3 行に折り返すことがありました。スイッチャーラベルとドロップダウンの全項目を whitespace-nowrap にし、国旗 + 言語名が常に 1 行に収まります。 フッターの言語リストは固定の 2 列グリッドから 1 行アイテムの折り返し行に変更 —「🇧🇷 Português (Brasil)」も名前の途中で折れなくなりました。

[1.119.4] — 2026-07-13

変更

  • LICENSE に作者を明記 — 著作権行は Sergei Emelianov (Fighter90) https://sergey-cv.com and career-ops-ui contributors になりました(MIT の正規本文は無変更)。新しい NOTICE.md がライセンスを詳細に解説:著作権者は誰か、MIT 許諾が正確に何をカバーするか(コード、ドキュメント、翻訳、ランディング、wiki)、何をカバーしないか(実行時のあなたのデータ、親プロジェクト、求人ボードのコンテンツ、商標)、サードパーティ構成要素の表(express/js-yaml — MIT、Astro/Tailwind — MIT、フォント Figtree と JetBrains Mono — SIL OFL 1.1、sharp — Apache-2.0)、任意の帰属表示の一文。

[1.119.3] — 2026-07-13

追加

  • SECURITY.md — CONTRIBUTING が指していたセキュリティポリシーがついに実在します:サポート対象バージョン、非公開報告フロー(リポジトリで GitHub の private vulnerability reporting を有効化 — Security タブ →「Report a vulnerability」)、localhost バインドの単一ユーザーアプリの脅威モデル(スコープ内:敵対的な求人経由の XSS / SSRF / パストラバーサル / シークレット漏えい / CSP の弱体化。スコープ外:自分の localhost への DoS と親プロジェクトの問題)、レビュアー向けのハードニング基準。

[1.119.2] — 2026-07-13

追加

  • CONTRIBUTING.md — ランディングと README がずっとリンクしていたコントリビューターガイドがついに実在します:セットアップ、プロジェクトマップ、セキュリティ/ノービルドの厳格ルール、テスト階層、スキャンソース追加の「2 つのレジストリ」ウォークスルー、×16 i18n 契約、コミット/PR 規約、リリースプロセス。
  • ランディングの言語フラグ — cvstart.org の言語スイッチャー、フッターの言語グリッド、「あなたの言語で読む」バナーに、各ロケールの国旗をエンドニムの横に表示するようになりました(アプリの言語 <select> と同じ地域指示子セット。国旗グリフのない環境では地域文字に退化)。
  • ランディングのフッター修正 — 機能が有効化されていないためリンク切れだった Discussions は、プロジェクトの wiki を指すようになりました。フッターには作者のクレジットを追加:Sergei Emelianov(sergey-cv.com · LinkedIn)。

[1.119.1] — 2026-07-13

修正

  • #/scan のソースフィルターがレジストリに追いつきました — Source ドロップダウンの背後にある静的な FALLBACK_SOURCES リスト(GET /api/scan/sources に到達できない場合のみ使用)は v1.87.0 以降、静かに遅れていました:オフラインフォールバックに 20 のプロバイダー(Amazon、Avature、SAP SuccessFactors、Get on Board、Dassault Systèmes、beesite、HigherEdJobs、JibeApply (iCIMS)、softgarden、Cornerstone、Phenom、Radancy、Deutsche Bahn、EchoJobs、TKMS、Heckler & Koch、Rheinmetall、LaraJobs、そして新しい Meituan / Tencent)が欠けていました。全 61 と同期し、クライアントのリストがサーバーレジストリから乖離すると CI を失敗させるドリフトテスト(値もラベルも)で保護されるようになりました。+1 テスト(1845)。

[1.119.0] — 2026-07-13

親 career-ops v1.19.0 パリティ + cvstart.org ランディングの刷新。

追加

  • 2 つの新スキャンプロバイダー — Meituan(zhaopin.meituan.com)と Tencent(careers.tencent.com):中国テック系ボードの認証不要な公開 JSON API。ホストから自動検出、または明示的な provider: で選択。キーワードごとのサーバーサイド検索・ページネーション・URL による重複排除つき — これで 61 アダプタ(英語圏 56 + ロシア系 5)。+20 テスト(1844)。
  • ランディングのコントリビューターブロック — cvstart.org にコードを提供した全員のアバターを表示(ビルド時に GitHub /contributors API から取得、ボットは除外)。16 言語すべてにローカライズされ、コントリビューターグラフ全体へのリンクつき。
  • ランディングのライブ GitHub スター数 — ヘッダーのバッジは訪問のたびにクライアント側で GitHub API から更新(ビルド時のスナップショットはフォールバック)。週次スケジュールの Pages 再ビルドがスナップショットとコントリビューター一覧を新鮮に保ち、CI の API 呼び出しはトークン認証になりました。

修正

  • Workday CXS リクエストがブラウザ風ヘッダーを送信(親 #1813)— Cloudflare 保護テナント(実例:geico)は通常の UA/accept-language/origin/referer を欠くリクエストに 500 を返します。フェッチャーは origin とサイトスラッグを CXS URL 自体から導出するようになりました。Glints リクエストにも同じブラウザ UA + origin/referer を追加 — どちらも http-json.mjs の共有定数 BROWSER_LIKE_USER_AGENT から。

[1.118.4] — 2026-07-10

修正

  • ロシアの IP から hh.ru スキャンが 0 件を返していた(地域サブドメインのリンク) — ロシアの住宅用 IP からだと hh.ru は検索を地域サブドメイン(sochi.hh.ruspb.hh.ru など)へ 302 リダイレクトし、求人リンクをそのサブドメインで返します。パーサーはタイトルリンクを固定ホスト https://hh.ru/vacancy/ で探しており、地域リンクを 1 件もマッチできず、完全に動作するスキャンが黙って 0 件を記録していました。現在は任意の *.hh.ru ホストを受け入れ(adsrv.hh.ru/click?… の広告は引き続き除外 — /vacancy/<id> パスを持たない)、各結果 URL を https://hh.ru/vacancy/<id> に正規化します。実地検証済み:以前 0 件だった sochi.hh.ru ページから 17 件の実求人が解析されます。+1 テスト(1824)。

[1.118.3] — 2026-07-10

修正

  • hh.ru がエラーなしで 0 件を返していた(VPN チェックの中間ページ) — hh.ru は VPN/プロキシと判定したネットワーク(データセンター IP)を /vpncheeck 中間ページ(「VPN мешает работе сайта」)へ 302 リダイレクトするようになり、このページは求人カードを 1 枚も含まない HTTP 200 を返すため、スキャンはエラーなしで 0 件を報告していました。スキャナーはレスポンスの最終 URL からリダイレクトを検出し、実行の残りの間 hh.ru を無効化し、正直なヒントを出力します:トラフィックは本当に住宅用 IP から出ている必要があります — ブラウザのトグルをオフにしてもシステム全体の VPN/プロキシは有効なままのことがあります。+1 テスト(1823)。

[1.118.2] — 2026-07-10

メンテナンス

  • ランディングのフォローアップ(#118)site/README.md を Astro 7(#116 のセキュリティアップグレード)に合わせて修正し、未使用 import を削除、ランディングのビルドスクリプトに実行可能なガードを 4 件追加: i18n パリティゲートが壊れた辞書で確実に失敗することを証明し、sync-assetssite/ の外に書き込まないことを保証 — スイート 1822。CodeQL アラート 2 件を解決(1 件はソース修正、1 件は意図されたビルド時動作として却下)。

[1.118.1] — 2026-07-10

修正

  • ロシア国外からの hh.ru スキャン — hh.ru が公開検索ページでロシア国外の IP に HTTP 451(地域的な法的ブロック)を返すようになりました。スキャナーは 451 を 403 と同様に扱います: 最初のブロック後、実行の残りで hh.ru を無効化し、ロシア IP / VPN 出口を案内する正直なログを残すため、残りのクエリや他の RU ソースを無駄にしません。ヘルプ §7 を全 16 言語で更新。テスト +1(1818)。

[1.118.0] — 2026-07-09

親 career-ops v1.18.0 パリティパック。

追加

  • 9 つの新しいスキャンプロバイダー — Cornerstone OnDemand (csod), Phenom (phenom), Radancy (radancy), Deutsche Bahn (deutschebahn), EchoJobs (echojobs), TKMS (tkms), Heckler & Koch (hecklerkoch), Rheinmetall (rheinmetall), LaraJobs (larajobs) — これでアダプターは 54 個。Lever アダプターは EU テナンシーのボード(jobs.eu.lever.co)も検出します。
  • トラッカーの Hired ステータス(親の states.yml パリティ): 受諾したオファーは独自の正規ステータス、お祝いバッジ、#/tracker の内定獲得バナーを持ちます。ファネルとコンバージョンのチャートは全ステージを通過したものとして数えます。
  • #/stats の累計タブ — 親の stats.mjs(累計トラッカー集計、累積ファネル率、スキャナー合計、ポータルカバレッジ)と salary-gap.mjs の報酬観測(希望 vs 求人提示 vs 実際、応募ごと)を読み取り専用で中継します。新ルート GET /api/stats/lifetimeGET /api/stats/salary-gap — ゼロトークンのシェルアウトで、親プロジェクトがなければ {available:false} に安全にフォールバックします。
  • 全 16 ロケールに 28 個の新しい i18n キー。ヘルプガイド §14/§26 を全言語で更新。

テスト

  • ユニットテスト +38(プロバイダーパリティ 3 スイート + リレー/ステータスルート) — 合計 1817

[1.117.2] — 2026-07-06

パリティ・シェルアウトの空トラッカー修正。 トラッカーに応募がまだ無い場合、親スクリプトはコード1と構造化された {error} JSONで終了します。フォローアップボードと不採用パターンタブはこれを「script-error」と表示していました。両ルートはこれを健全な空状態(available:true, empty:true)として中継し、UIは正直な「まだ何もない」メッセージを表示します。実際の親でライブ検証済み。

新規: なし。

[1.117.1] — 2026-07-06

v1.117.0 のハードニング(CodeQLトリアージ)。 3つのシェルアウト・エンドポイント(GET /api/followupPOST /api/followup/seedGET /api/stats/patterns)に共有のIP別リミッターを適用(リクエストごとに子プロセスを生成; ループバックではno-op)。CVに追加のURLテキスト抽出は、タグを不動点まで除去した後、残った </> をすべて削除 — LLMプロンプト用テキストとして証明可能に完全なサニタイズ。有効な入力の挙動は不変。

新規: なし。

[1.117.0] — 2026-07-06

親パリティパック — 親 career-ops の6つの機能をUIへ。 (1) #/followupフォローアップ・ケイデンスボード: followup-cadence.mjs による応募ごとの緊急度(🔴/🟠/🟡/🔵)+ フォローアップ日をシードボタン(followup-seed.mjs --backfill)。(2) 不採用パターン: 統計の4つ目のタブが analyze-patterns.mjs(読み取り専用)を実行 — 結果の内訳、推奨、ATSベンダー別前進率。(3) CVに追加: CV StudioのカードがURLまたは貼り付けテキストを、その出典のみに基づくATS箇条書きに変換(提案のみ、書き込みなし; URLフェッチはSSRF保護)。(4) 新スキャンプロバイダ4つ — beesite、HigherEdJobs(RSS)、JibeApply(iCIMS)、softgarden — レジストリは50アダプタ(45 EN + 5 RU)になり、すべてScanのドロップダウンに表示。(5) Applyチェックリストに失格要件の事前スキャンステップ。(6) reconcileランナー(/api/run/reconcile)。シェルアウトのルートは親スクリプトがなければ正直に「利用不可」を表示。

  • 新ルートモジュール server/lib/routes/followup.mjs(31番目)+ 新ルート + ソース/アダプタ8ファイル。テスト: 6 + 7 追加; スイート 1737 → 1750。新しいi18nキー41件×16。ヘルプ §13/§17/§24/§26 を×16拡張。

新規: GET /api/followupPOST /api/followup/seedGET /api/stats/patternsPOST /api/cv-studio/add-entryPOST /api/run/reconcile

[1.116.0] — 2026-07-06

使用量メーターの作り直し + 初のE2Eウィジェットテスト。 AI使用量メーター(v1.114.0)を正しく固定しました:左サイドバーの下部に固定され(サイドバー全幅、同じ表面)、自身の高さ分だけサイドバー下部に余白を確保してメニューが決して隠れません — ナビとバージョンフッターは常にその上をスクロールします。リアルタイム更新(15秒間隔 + タブフォーカス + ルート変更)で、各ウィンドウ行は常に100%の「割合」ではなく実際の**<トークン> · <推定コスト>(バーは30日ウィンドウ基準)を表示します。さらに、CVインポーターの恒久的な typeof バリアが、繰り返されるCodeQLの型混同の誤検知を根本で閉じ、新しいPlaywrightのE2Eテスト**が2つの常駐ウィジェットを実ブラウザで検証します。

  • public/js/lib/usage-hud.js + app.cssserver/lib/cv-import.mjs。テスト: tests/playwright-widgets.mjs(2 E2E)+ tests/usage-hud.test.mjs(10)。ヘルプ§6を×16拡張。

新規: なし。

[1.115.0] — 2026-07-06

デザインの磨き込み(保守的、コーラルのブランドは維持)。 共有デザインシステムへの軽い洗練パス — 構造変更なし、パレット変更なし。ダッシュボードのメトリクスカードはホバー時にわずかに浮き上がり、コーラルの枠線を帯びます(クイックアクションタイルと同じ)。コンテンツカードもわずかに浮きます。primary / dark / danger ボタンは静止時の影と穏やかなホバーリフトで奥行きを得ます。大きな数字は tabular-nums で揃います。インタラクティブなコントロールは2pxのキーボードリングの背後に柔らかなコーラルのフォーカスハローを受け取ります。すべてのモーションは prefers-reduced-motion を尊重し、ハローはコントロールに限定されます — グローバルな *:focus-visible ではありません。

  • CSSのみ(public/css/app.css)。マークアップ・i18n・ルート・CSPの変更なし。テスト: tests/design-polish-v1115.test.mjs(5)。Playwrightでライブ検証。

新規: なし。

[1.114.0] — 2026-07-06

サイドバーのAI使用量・コストメーター(左下)。 コンパクトな使用量セクションが、すべてのページのサイドバー下部に表示されます(サイドバーがなければ左下の固定カード、RTLでは右下)。24h / 7d / 30d の各ウィンドウのLLMトークン使用量を <トークン> · <割合%>(全期間に対する割合)で緑のメーターバーとともに表示し、24時間の推定コストのフッターを添えます。データは data/llm-usage.jsonl の読み取り専用 GET /api/usage 集計(ローカルのみ)で、#/usage ページと同じソースです。コストは推定であり、手動モードの実行は無料でカウントされません。折りたたみ可能 — ヘッダーで切り替え、状態は保持されます。

  • 新しいクライアントウィジェット public/js/lib/usage-hud.jsindex.html から読み込み、バージョンフッターの上のサイドバーにマウント(固定コーナーのフォールバック)。CSP安全、テーマ対応 + RTLミラー。新しいサーバールートなし。テスト: tests/usage-hud.test.mjs(8)。新しいi18nキー3件×16。

新規: なし。

[1.113.0] — 2026-07-06

すべてのページに浮かぶ「ヘルプに質問」アシスタント。 グラデーションのロボットチャットボタンが、すべてのページの右下(RTLでは左下)に浮かびます。クリックすると、あなたの言語のアプリ内ヘルプガイドのみに基づいて使い方の質問に答えるコンパクトなチャットが開きます — #/docs-assistant ページと同じエンドポイント(POST /api/docs-assistant/ask)なので、CV・プロフィール・トラッカーは読みません。LLMキーがあればライブ、なければすぐ実行できるプロンプト。ヘッダーにはロボットアバター + オンライン状態、スターターチップでよくある質問を入力、Escまたは外側クリックで閉じ、#/docs-assistant ページでは非表示。

  • 新しいクライアントウィジェット public/js/lib/docs-fab.jsindex.html からグローバルにマウント。CSP安全。app.css にテーマ対応 + RTLミラーのスタイル。新しいサーバールートなし。テスト: tests/docs-fab.test.mjs(8)。新しいi18nキー6件×16。ヘルプ§1をその場で拡張。

新規: なし。

[1.112.0] — 2026-07-06

ドキュメントとQAの統合。 ユーザーに見えるコード変更なし。SDD規約ドキュメント(docs/sdd/CONVENTIONS.md)を現在の30ルートモジュール(以前は24)と現在のテスト基準に更新し、全プロジェクト確定QAプロンプト(qa/QA-REGRESSION-PROMPT.md)を統合しました — リリース手順を最新化(v1.111、parentVersion 1.17.0、リリーストリガー公開)、§14追加表を修正(Scan除外をv1.109.0に再ラベル)し、v1.111のCodeQLクローズアウトを追加 — 全機能の単一リグレッションプロンプトとして単独で成立します。過大アップロード分岐のカバレッジテストを1件追加。

新規: なし。

[1.111.0] — 2026-07-06

セキュリティ — CodeQLバックログの解消。 残る静的解析の指摘を握りつぶすのではなく原因箇所で閉じる、多層防御の強化3件。stripDangerousMarkdown途中で切れた 危険タグの開始(<script/<iframe/… で終わるペイロード)の < をエスケープするようになり、出力に生きた危険タグが残らないことを保証します。CVインポートはアップロードされたバッファのサイズを明示的な Number() 変換で読み取ります — 型混同のバリア。モードのロール行は、保存された関数ではなく String.replace で補間されるテンプレート文字列になり、動的ディスパッチ呼び出しを完全に排除しました。ユーザーに見える挙動の変化はありません。

  • server/lib/security.mjsserver/lib/cv-import.mjsserver/lib/prompts.mjs。テスト: tests/security-hardening-v1111.test.mjs(7)+ v1108ガードテスト更新。i18n/ヘルプ/ルート変更なし。

新規: なし。

[1.110.0] — 2026-07-06

ドキュメント & QA 更新(全言語)。 コード変更なし。プロジェクト全体のQAプロンプトがv1.109.0に更新され、v1.98→v1.109を扱う新§14が追加、UX監査とデザインエクスポートのプロンプトが現在の画面群を反映。v1.100–v1.109で追加された全ヘルプ段落が全16言語に翻訳されました。

新規: なし.

[1.109.0] — 2026-07-06

Scanの除外フィルター + パイプライン概要(Webレイアウトパリティ)。 #/scan検索ボックスがカンマをORとして扱い(「探す役割」)、新しい除外フィールドは会社/役割/場所にカンマ区切りの語(例: senior, staff)を含む行を隠します。両方とも保存済み検索に記憶されます。#/pipelineにはコンパクトな概要ストリップがパイプラインを一目で表示 — 受信 N追跡 N、トラッカーの Applied / Responded / Interview / Offer の数、各チップは #/tracker にリンク。

  • クライアントのみ(新ルート/書き込みなし)。public/js/views/scan.js + public/js/views/pipeline.js。テスト: tests/scan-pipeline-ui-v1109.test.mjs(2)。新しいi18nキー4件×16。ヘルプ§7 + §8をその場で拡張。

新規: なし。

[1.108.0] — 2026-07-06

セキュリティ強化(CodeQLトリアージ第2弾)。 さらに軽微な3件を修正: モードプロンプトビルダーがロケールの役割行を自身のキー + typeof === functionで解決し、改ざんされたロケールがプロトタイプメソッドへディスパッチできないようにし(unvalidated-dynamic-method-call);PDFファイル名スラッグを正規表現の前に200文字に制限し、全ハイフン入力がバックトラックしないようにし(多項式ReDoS);ドキュメントインポートが配列のfilename(繰り返しヘッダー)を文字列に強制変換します(type-confusion)。有効な入力に対する挙動変化なし。

  • server/lib/prompts.mjsserver/lib/routes/runners.mjsserver/lib/cv-import.mjs + tests/security-hardening-v1108.test.mjs(3)。v1.106–v1.108で静的解析のバックログは167から約14に減り、真にセキュリティ関連の指摘はすべて修正、残り(ガード/サニタイズ済みの誤検知 + ノートレベルのlint)は根拠付きで却下。

新規: なし。

[1.107.0] — 2026-07-06

サニタイザー強化(保存時XSSの多層防御)。 stripDangerousMarkdown — 保存済みの履歴書/求人マークダウン内の危険なHTMLを無害化し、描画時エスケープのクライアントを迂回する消費者も安全にする — が、タグ除去を不動点まで(変化がなくなるまで反復)実行し、除去がペイロードを再構成する場合(例: <scr<script></script>ipt>)を捕捉し、末尾にゴミが付いたscript/styleなどの終了タグ(</script foo>)と閉じられていない実行オープナー(<script …>)を除去します。有効なマークダウンの挙動は変わらず、より多く除去するだけです。

  • server/lib/security.mjs: 不動点ループ(8回制限)+ [^>]*> 終了タグパターン + 未クローズオープナー除去。tests/cv-xss-bypasses.test.mjs に回帰ケース+3。権威あるXSS境界は依然として出力エスケープ(UI.md)であり、これは保存時保証を強化し、対応するCodeQLの指摘を解消します。

新規: なし。

[1.106.0] — 2026-07-06

セキュリティ強化(CodeQLトリアージ)。 静的解析のバックログを精査し、実際の(軽微だが)3件を修正しました: ルート描画のエラー経路がエラーメッセージをDOMに到達する前にエスケープするようになり(サーバーエラーがユーザー入力を反映しうるため、信頼できないものとして扱う — XSS境界)、プロフィール/設定のプロパティ書き込みが**__proto__ / constructor / prototype キーを拒否**します(念のためのプロトタイプ汚染ガード — キーは固定フィールド仕様から来るもので、生のリクエスト入力ではない)。残りのアラートの大半は、スキャナーの正当な data/* の読み書きや、既に独自レートリミッターを備えたルートに対する誤検知で、根拠付きで却下しました。

  • public/js/router.jsinnerHTML の前に UI.escapeHtmlerr.message をエスケープ; server/lib/routes/content.mjsserver/lib/routes/config.mjs はプロトタイプキーをガード。有効な入力に対する挙動変化なし。テスト: tests/security-hardening-v1106.test.mjs(3)。新しいi18nキーなし。

新規: なし。

[1.105.0] — 2026-07-06

AI使用量とコストのページ。 新しいAI使用量ページ(サイドバー、ヘルスの隣)は、ライブのAI生成 — 評価・レポート・チャット — に費やしたトークンを、過去24時間・7日・30日・全期間にわたってプロバイダーごとに表示し、推定USDコストを併記します。すべてのライブ呼び出しは小さな {provider, in, out} レコードを data/llm-usage.jsonl に追加します(どこにも送信されません)。キーなしの実行(手動モード)はコストがかからず、記録されません。

  • 新ルートモジュール(30番目) server/lib/routes/usage.mjsGET /api/usage(読み取り専用の集計) + server/lib/llm-usage.mjs(recordUsage がAnthropic/OpenAI/Geminiの使用量形式を正規化してbest-effortで追加、readUsage/aggregate が24h/7d/30d/全期間の窓 × プロバイダーで集計) + server/lib/llm-pricing.mjs(編集可能なプロバイダーごとの $/1M トークン価格表 — トークンは正確、ドルは概算定価でプランに合わせて修正可能、請求されない)。記録はディスパッチ地点(runActiveProvider + routes/llm.mjs)にフックされます。
  • 新ビュー public/js/views/usage.js(#/usage、期間タブ)。テスト: tests/usage-routes.test.mjs。新しいi18nキー17件×16(usage.* + nav.usage)。ヘルプ§6をその場で拡張。

新規: server/lib/routes/usage.mjs; server/lib/llm-usage.mjs; server/lib/llm-pricing.mjs; public/js/views/usage.js.

[1.104.0] — 2026-07-06

スキャン表の会社ロゴ(プライバシー保護)。 アプリ設定の新しい外観トグル — スキャン表に会社ロゴを表示(既定オフ) — が #/scan で会社名の隣にロゴを描画します。ロゴは会社自身のドメインから取得したファビコンで、サーバー側でプロキシされます(GET /api/logo)。そのためサードパーティのロゴサービスがあなたの見ている雇用主を知ることはありません。共有求人ボード(Greenhouse、Lever、Ashby など)の掲載はボードのアイコンではなく色付きの文字バッジを表示し、読み込みに失敗したロゴも同じバッジにフォールバックします。

  • 新ルートモジュール(29番目) server/lib/routes/logos.mjsGET /api/logo?domain=。ドメインを検証し(スキーム/パス/ループバックなし)、SSRF安全な safeGet(新しい binary モードが生バイト + content-type を返す。DNSピン留め・リダイレクト検証・サイズ上限は不変)で /favicon.ico を取得し、HTMLエラーページを画像として提供しないよう画像マジックのスニッフィングを行い、ヒットミスをメモリLRUにキャッシュし、ディスクには何も書き込みません
  • 新クライアントライブラリ public/js/lib/company-logo.js(window.CompanyLogo): localStorageフラグで既定オフ。共有ATSホストはスキップして決定的な文字アバターを使用。CSP安全な img.onerror フォールバック。テスト: tests/logo-routes.test.mjs。新しいi18nキー5件×16(appear.*)。ヘルプ§2をその場で拡張。

新規: server/lib/routes/logos.mjs; public/js/lib/company-logo.js.

[1.103.0] — 2026-07-06

設定: 「AI CLIツール」 — 何がインストールされているか。 career-opsはClaude Codeベースですが、オープンなスキル標準の任意のエージェントCLIで動作します。アプリ設定(#/config)の新しいAI CLIツールタブは、Claude Code、Codex、Gemini CLI、OpenCode、GitHub Copilot CLI、Qwen、Antigravityのうち、サーバーを実行しているマシンに何がインストールされ、そのパスがどこかを表示します。これは読み取り専用のPATHスキャンです: 各バイナリの存在を確認するだけで決して実行せず(--versionなし、実行なし)、何も書き込まず、ユーザーデータに触れません。

  • 新ルートモジュール(28番目) server/lib/routes/cli-detect.mjsGET /api/cli-detect。検出は固定7件の許可リストから process.env.PATH を通じてバイナリのパスを解決します(Windowsの.cmd/.exe/.batシム、POSIXの実行ビット)。PATH上の悪意あるファイルがこのルートで実行されることは決してありません。
  • public/js/views/config.jsの新しい「AI CLIツール」タブ(遅延読み込み、#/config?tab=cliでディープリンク)。テスト: tests/cli-detect-routes.test.mjs。新しいi18nキー8件×16(cli.* + config.tabCli)。ヘルプ§2をその場で拡張。

新規: server/lib/routes/cli-detect.mjs.

[1.102.0] — 2026-07-05

「ガイドに質問」 — アプリ内ヘルプガイドに基づくチャット。 新しいガイドに質問 💬ページ(サイドバー、ヘルプの下): 「求人ポータルはどうスキャンしますか?」のような質問を入力すると、あなたの言語のアプリ内ヘルプガイドのみから回答が得られます — 使用したセクションを表示し、あなたの履歴書・プロフィール・求職活動は一切読み取りません。あなたのことではなく、アプリの使い方についてです。LLMキーがあればライブ回答、なければ関連するヘルプセクションが既に入ったすぐ実行できるプロンプトを渡します。

  • 新ルートモジュール(27番目) server/lib/routes/docs-assistant.mjsPOST /api/docs-assistant/ask依存関係なしの検索: あなたの言語のヘルプ文書を ## セクションに分割し、質問とのキーワード重複でスコア付け — 上位セクションをインライン化し、モデルはそこから回答するかガイドが扱っていないと述べます(機能/ルートの捏造なし)。共有プロバイダーカスケード、手動フォールバック、レート制限、書き込みなし、ユーザーデータを読みません。
  • 新ビュー public/js/views/docs-assistant.js。テスト: tests/docs-assistant-routes.test.mjs。新しいi18nキー14件×16(docs.* + nav.docsAssistant)。ヘルプ§1をその場で拡張。

新規: server/lib/routes/docs-assistant.mjs; public/js/views/docs-assistant.js.

[1.101.0] — 2026-07-05

CV Studio: 特定の求人に合わせて履歴書を最適化し、カバーレターを作成 — リクルーターのチェックリストでゲート。 #/cv-studioに新しい求人に合わせて最適化カード: 求人内容(任意で目標の役割/ヘッドライン)を貼り付けると、CV Studioがその求人に合わせた履歴書と対応するカバーレターを作成し、渡す前に両方をチェックリストゲートに通します — errorはブロック(結果を見る前に修正)、warnは助言。この仕組みはキャリアコーチングの実践を汎用ルールに蒸留したものです — リクルーターは数秒で読むため、関連経験は上に、ヘッドラインは求人の役割に一致、成果には具体的な数値、カバーレターは「要件↔あなたの合致する事実」という単一のブリッジを持つ短いティーザー。あなた自身の履歴書・プロフィール・ツーページャーのみに基づき決して捏造しません — 企業・役割・経歴をハードコードしません。

  • 新エンドポイント POST /api/cv-studio/tailor(既存のcv-studioモジュールを拡張 — 27番目のモジュールではない): buildTailorPrompt + 汎用の TAILOR_INSTRUCTIONS ゲート、bundleProjectContextに基づき、共有プロバイダーカスケード、キーがなければ手動プロンプト、レート制限、書き込みなし。結果は共有の report-export.js バーでMarkdown / PDF / DOCX にエクスポート。
  • テスト: tests/cv-studio-routes.test.mjsに+3。新しいi18nキー10件×16(cvs.tailor*)。汎用リファレンス docs/prompts/resume-cover.md。ヘルプ§24をその場で拡張。

新規: docs/prompts/resume-cover.md.

[1.100.0] — 2026-07-05

ツーページャー: 履歴書からのAI自動入力+プレビュー+PDF/DOCX/Markdownエクスポート。 ツーページャー(#/two-pager)は次の役割に本当に望むものを記録しますが、これまでは各項目を手入力するかプロンプトを別ツールにコピーする必要がありました。今回、✨ AI入力アシスタントが設定済みプロバイダーでライブ実行されます — 履歴書+プロフィールのみを読み込み(bundleProjectContext、捏造なし)、すべての項目(私は誰か/好きなこと/必須条件/嫌いなこと/絶対NG/譲れない点/目標環境)を下書きしてフォームに入力し、確認・編集・保存できます。APIキーがなければ従来どおりプロンプトコピーのモーダルにフォールバックします。新しい**👁 プレビューとエクスポートボタンはツーページャーを整形済み文書として描画し、.mdをダウンロード/PDFで保存/DOCXで保存/コピー**のバーを表示します。

  • 依存関係なしの.docxエクスポート。 新規server/lib/docx.mjsが最小限だが有効なOffice Open XML .docx(4つのOOXMLパートのDEFLATE ZIP、エントリごとにCRC-32)を生成します — 新しいランタイム依存なし(依存はexpressjs-yamlのまま)。新ルートPOST /api/export/docx(server/lib/routes/export.mjs、26番目のルートモジュール。ステートレス、200 KB制限、書き込み・LLM・URL fetchなし)。共有のpublic/js/lib/report-export.jsに統合したため、市場レポート、キャリアプラン、キャリアオリエンテーションのレポートもDOCXエクスポートに対応します。
  • ライブ自動入力は共有プロバイダーカスケード(runActiveProvider / providerAvailable)を使用し、返されたYAMLはパースされて制限付きツーページャー形状(parseYamlFields + normalizeTwoPager)に強制変換されます — 不明なキーは破棄、配列/文字列は上限あり。手動モードは維持。
  • テスト: tests/export-routes.test.mjs。新しいi18nキー4件×16(export.saveDocxtwoPager.previewtwoPager.aiFillingtwoPager.aiFilled)。

新規: server/lib/docx.mjs; server/lib/routes/export.mjs.

[1.99.0] — 2026-07-05

ポータル状態ページ#/portals)。スキャナは portals.yml の会社群を監視します。ATS スラッグが静かに壊れると、その雇用主は以降のすべてのスキャンから静かに消えます。新しい Portals ページは監視中の各社を一覧し、Check portal health で各 careers_url を DNS ピン留めの safeGet(SSRF 安全)で探査し、死んだもの(404 = 静かに除外)を印付けします — 読み取り専用。またレビューに従い v1.98.0 のバグレポーターを強化:エラーリングバッファがネットワークの fetch 失敗を捕捉し、スクラバがラベルなしのプロバイダキーを伏字にします。

新規: server/lib/routes/portals.mjs; public/js/views/portals.js.

[1.98.0] — 2026-07-05

アプリ内バグレポーター(親プロジェクトの web-v0.2.0 Web とのパリティ)。通知ドロワーの 🐞 Report a bug ボタンが、プライバシー下限を守る診断スナップショットを収集します — バージョン、現在の画面、ブラウザ、/api/health のチェック要約、新しいクライアント側リングバッファからの直近 20 件のエラー — さらに決定的な重複排除フィンガープリント(co-web-<base36>)を付け、正確な Markdown を確認させてから、事前入力済みの GitHub Issue を開きます。自動送信は一切なく、CV・プロフィール・回答・求人 URL・キーを決して含みません。新ライブラリ logbuf.js + bug-report.js;11 個の i18n キー ×16;tests/bug-report.test.mjs

新規: public/js/lib/logbuf.js; public/js/lib/bug-report.js.

[1.97.1] — 2026-07-05

レビュー起点の堅牢化とドキュメントのパリティ(v1.97.0 のフォローアップ)。 AI レビューログを一巡したところ、実際の修正が浮かび上がりました:

  • fit-score.js(スキャン 適合バッジ)。 salaryFloor() は年額未満のレートをもう偽の年額下限に格上げしません — 「at least 500 EUR/day」「$80/hr」「6000 monthly」は 500k/80k のディールブレーカーではなく null を返すようになりました。国のマッチングが単語単位(\b…\b)になり、「Germany」が形容詞「German」(あるいは「Nigerian」内の「Nigeria」)にマッチして誤った必須条件-他地域違反を発火させることがなくなりました。tests/fit-score.test.mjs にテスト +3。
  • ドキュメントのパリティ。 すべてのローカライズ済み README が 16 ロケール を一貫して表示するようになりました — Help 行の件数/一覧(×13)とローカライズセクションの本文 + 「N 個すべてのファイルにキーを追加」ノート(×8)が、まだ v1.85 以前の件数(8/9)のままでした。アプリ内ヘルプ §17 のアダプタ件数は、16 バンドル全体で 46 アダプタ — 英語 41 + ロシア語 5 に修正されました。

適合バッジのヒューリスティック以外に動作変更なし。新しいルート、キー、i18n の追加なし。

[1.97.0] — 2026-07-05

Dassault Systèmes スキャナソース + 3方面の品質スイープ。

  • 新しいスキャンソース — Dassault Systèmes(親 career-ops パリティ、#1498)。 server/lib/sources/dassault.mjs + server/lib/portals/adapters/dassault.mjs は、親プロジェクトのゼロトークン Exalead「カード検索」プロバイダ(3ds.com/careers/jobs の背後にある公開フィード)をそのまま反映します。単一のグローバルエンドポイントなので、プロバイダ選択(provider: dassault)または 3ds.com ホストからの自動検出で、redirect:'error' とともに www.3ds.com に SSRF ホスト固定されます。XML は DOM なし(<Hit> ごとの <Meta> マップ)で解析され、都市/国はローカライズされたカテゴリ文字列から取得され、求人はその公開 URL が *.3ds.com 上にある場合のみ保持されます。レジストリは 46 アダプタ(EN 41 + RU 5)を提供するようになりました。ALL_ADAPTERS の件数、ソート済み id、/api/scan/sources の EN セットアサーションが 40 → 41 に引き上げられました。スイート tests/sources-dassault.test.mjs(10 ケース)。
  • 親プロジェクトの堅牢性修正を移植。 Avature パーサは 2 つのライブテナントのマークアップ変種(位置インデックスの接尾辞付き article--result + クラスなしの JobDetail タイトルアンカー、#1541)を許容するようになりました。Get on Board は 0/負の published_at を防御します(もう誤った 1970 年の日付はありません)。SuccessFactors は最終ページに上限を設け、MAX_JOBS を超えないようにします(#1528)。
  • サーバ監査の修正。 safe-fetch は上限超過のレスポンスでもうハングしません — サイズ上限のパスが、破棄されたストリームが決して発火しない 'end' イベントを待つ代わりに、Promise を直接解決するようになりました(大きなページの /api/pipeline/preview + 自動パイプラインのフェッチを修正)。SSE stream.* のアクティビティログが再び到達可能になりました(/api/stream/ チェックが包括的な「GET をスキップ」ガードより上に移動)。
  • SPA 監査の修正。 #/stats タブスイッチャーが非同期レンダーの競合を防御します — 遅いタブの結果が、ユーザーがすでに切り替えた新しいタブを上書きできなくなりました。mock interview とネットワーキングの削除確認は、適切なタイトル + 本文を渡すようになりました(もう本文が空のダイアログはありません)。
  • 翻訳の修正。 未翻訳の辞書値を修正 — ウクライナ語 config.modes*(Adaptive Framing / Exit Narrative / Location Policy)、ロシア語 eval.jdLbl(「Job Description」)、イタリア語 dash.quick.contactoSub(「referral」→「segnalazione」)— さらに ru/uk/ja/ko/zh-CN/zh-TW の CHANGELOG で英語の 16 ロケール の定型文をローカライズしました。

新規: server/lib/sources/dassault.mjs; server/lib/portals/adapters/dassault.mjs.

[1.96.0] — 2026-07-04

キャリアの方向性(Epic 27)。 新しい #/orientation ページは「どの方向が実際に自分に合うのか?」に答えます — 職業適性検査で得られるような読み解きですが、アンケートではなく、あなた自身の CV とプロフィールから推測します。プロフィールを生成 をクリックすると、モデルはあなたの 最も適したキャリアベクトル(8 つのアーキタイプ — 機能主義者、管理者、コミュニケーター、スペシャリスト、アナリスト、イノベーター、マネージャー、アントレプレナー — のうちどれが合うか、根拠とともに)、キャリアタイプの傾向、おすすめの職種、CV に結び付いた職業上の強み、働き方の傾向、そして開発の推奨事項を返します。これは あなたの CV がどう読めるかについての AI による振り返りであり — 心理検査ではありません:実績を捏造することはなく、数値スコアを測定されたものであるかのように報告することもありません。Markdown または PDF にエクスポートでき、ディスクには何も書き込まれません。

  • 新しいルート server/lib/routes/orientation.mjs(24 番目のルートモジュール)— POST /api/orientation/generate は共有プロバイダカスケードを通じて CV+プロフィール+ツーページャー+メモリからプロフィールのプロンプトを構築し、コピー&ペーストの手動フォールバックと ファイル書き込みなし を提供します。
  • Growth ナビゲーショングループの下で、Markdown/PDF/コピーのために report-export.js を再利用します。
  • テスト:tests/orientation-routes.test.mjs(振り返りのフレーミング / 捏造されたスコアなし、CV/プロフィールをシードにした手動モード)。新しい i18n キー 7 個 ×16 ロケール、ヘルプ §28 ×16。

新規:#/orientationserver/lib/routes/orientation.mjs

[1.95.0] — 2026-07-04

キャリアプラン(Epic 26)。 新しい #/career-plan ページは、あなたの CV とプロフィールを、具体的でパーソナライズされた成長プランに変えます。期間(6/12/24 か月)と任意の フォーカス を選ぶと、モデルは — あなたの CV、プロフィール、two-pager、メモを読んで — 出発点のスナップショット、強み/成長の SWOT、SMART / OKR / WOOP としての目標、代替の進路、ハード/ソフトスキルの計画、月ごとのロードマップ、進捗管理の方法、落とし穴、そしてサポートの一手を書き出します。あなたの資料が実際に示していることから先を計画し、あなたの経歴について事実を捏造することは決してありません。インラインで編集し、ユーザーレイヤー(config/career-plan.md)に 保存 し、Markdown または PDF に エクスポート できます。

  • 新しいルート server/lib/routes/career-plan.mjs(23 番目のルートモジュール)— GET/PUT /api/career-plan(config/career-plan.md に書き込み)+ POST /api/career-plan/generate(共有プロバイダーカスケード、手動フォールバック、捏造なし)。PATHS.careerPlan
  • 共有ヘルパー report-export.js(v1.94.0)を Markdown/PDF/コピーに再利用し、新しい 成長 ナビゲーショングループを追加。
  • テスト: tests/career-plan-routes.test.mjs(範囲、GET/PUT のラウンドトリップ、期間を踏まえた CV/プロフィールをシードしたプロンプト)。16 ロケール すべてに 20 個の新規 i18n キー、ヘルプ §27 16 言語すべて。

新規: #/career-planserver/lib/routes/career-plan.mjsPATHS.careerPlan

[1.94.0] — 2026-07-04

統計、刷新(Epic 25)。 #/stats ページは、実際のグラフと大幅に増えたデータを備えた、3 つのタブからなる 統計 セクションになりました。新しい 市場レポート タブは、あなたが選んだ地域と通貨で、あなたのターゲット職種の給与および労働市場分析をモデルに求めます — エグゼクティブサマリー、P10/P25/P75/P90 パーセンタイル付きのグレード別給与、上位の雇用主、需要のあるスキル一覧、福利厚生の頻度、オフィス/ハイブリッド/リモートの内訳、12〜24 か月のトレンド、そして交渉ガイダンス。すべての数値は、スクレイピングしたデータとしてではなく、モデルの知識に基づく方向性の推定値 として明示されます。新しい マイパイプライン タブは、あなた自身のトラッカーをチャート化します: スコア分布、ステータスファネル、上位の企業と職種、時系列の応募、そしてコンバージョン率。元のターゲット職種ビュー(国別の求人/給与 + 保存したスナップショットのトレンド)は 3 つ目のタブに移り、通貨セレクター職種別の求人 概要を備えるようになりました。

  • どのレポートもエクスポート — 共有ヘルパー report-export.js を介して、Markdown または PDF にエクスポートするか、コピーします(Markdown blob のダウンロード。PDF は既存のインライン PDF ランナー経由)。
  • 新しいルート server/lib/routes/market.mjs(22 番目のルートモジュール)— POST /api/stats/market は、あなたの CV/プロフィール(そのためあなたのターゲット職種を把握しています)、地域、通貨から市場分析プロンプトを構築し、共有プロバイダーカスケードを通じて実行し、キーがなければコピー&ペースト用のプロンプトにフォールバックします。ディスクへの書き込みなし。
  • テスト: tests/market-routes.test.mjs(地域/通貨の範囲、正直さを明示したプロンプト、CV/プロフィールをシードした手動モード)。16 ロケール すべてに 36 個の新規 i18n キー、ヘルプ §26 16 言語すべて。

新規: タブに刷新された #/statsserver/lib/routes/market.mjspublic/js/lib/report-export.js

[1.93.0] — 2026-07-04

メモリレイヤー(Epic 24)。 新しい #/memory ページには、アシスタントが すべての タスクで念頭に置く、短く編集可能な「私についてこれを覚えておいて」というメモが保存されます:

  • 一つのメモをどこでもbundleProjectContext にインライン展開されるため、メモはすべての AI リクエスト(評価、模擬面接、ネットワーキング、CV Studio)に すべての プロバイダーを横断して自動的に届きます。一度書けば、すべてを方向づけます。
  • 事実ではなく方向づけ — あなたの好みや働き方(トーン、フォーマット、deal-breaker、ペース)を捉えるものであり、あなたの経歴に関する新しい事実の主張は決して含みません — それらは今も CV、プロフィール、two-pager にのみ存在します。ユーザーレイヤーの config/memory.md に保存され、更新で上書きされることはありません。
  • あなたのデータから提案POST /api/memory/suggest はあなた自身の応募トラッカーから行動パターンを抽出し、あなたがレビューして編集するための箇条書きを下書きします。トラッカーを読むだけで、事実を捏造することは決してなく、ライブ呼び出しも行いません。

新規: server/lib/routes/memory.mjs(21 番目のルートモジュール — GET/PUT /api/memory + POST /api/memory/suggest)、public/js/views/memory.jsPATHS.memory、そして bundleProjectContext に追加された config/memory.md ブロック。16 ロケール すべてに 11 個の新規 i18n キー。テスト: tests/memory-routes.test.mjs

[1.92.0] — 2026-07-04

CV Studio(Epic 21)。 新しい #/cv-studio ページは、あなたの CV に正直で、ほとんどローカルで動く 3 つのツールを提供します:

  • 履歴書診断 — 決定論的な 0–100 のスコアと、各チェックの説明(定量化されたインパクト、弱い動詞、バズワード、長さ、コアセクション、連絡先情報)。純粋なクライアントサイド(window.CvDiagnostics)— LLM なし、捏造なし、すべての指摘が説明されるので、何を変えるかはあなたが決めます。
  • プライバシーマスク — CV をサンプルやスクリーンショットとして共有する前に、PII(メール、電話番号、リンク/ハンドル、住所、任意で名前 → イニシャル)を伏せ字にします。すべてブラウザ内で実行され(window.CvPrivacy)、何を伏せ字にしたかを正確に報告し、原文を保存することは決してありません。
  • Make it human / voice match — 硬い一文や段落を貼り付けると、voice-dna.mdwriting-samples/ にサーバー側で基づいて、あなたの声で書き直します。厳格なガードレール: 並べ替え・引き締め・声の再構成はできますが、テキストにまだ存在しない事実・指標・実績を持ち込むことは決してありません。共有プロバイダーカスケードを通じてライブ実行するか、キーがなければコピー&ペースト用のプロンプトを返します。

新規: server/lib/routes/cv-studio.mjs(20 番目のルートモジュール — POST /api/cv-studio/humanize)、public/js/views/cv-studio.jspublic/js/lib/cv-diagnostics.jspublic/js/lib/cv-privacy.jsPATHS.voiceDna + PATHS.writingSamplesDir16 ロケールすべてに 29 個の新規 i18n キー。テスト: tests/cv-diagnostics.test.mjstests/cv-studio-routes.test.mjs。(テンプレートギャラリー、Word エクスポート、求人票 PDF アーカイブは CV Studio の後続作業として追跡されています。)

[1.91.0] — 2026-07-04

ネットワーキングと企業の詳細リサーチ(Epic 16)。 新しい #/networking ページは、企業を面接獲得のための実行可能なプランに変換します。あなたの CV・プロフィール・two-pager に基づいています:

  • 企業ドシエ — 企業が何をしているか、引用に値する最近のシグナル、そしてあなたの実際の経歴から引き出した「なぜ自分が合うのか」のフックをまとめた簡潔なブリーフ。
  • 誰に連絡すべきか — 3〜5 人のターゲットペルソナ(採用マネージャー、社内リクルーター、チームのシニア IC、温かい/同窓のつながり)と、それぞれを見つけるための具体的な LinkedIn 検索文字列。実在の名前を捏造することは決してありません。
  • 最も温かい紹介ルートあなたの経歴にとって最も現実的な温かい入り口(共通の雇用主/学校/コミュニティ、2 次のつながり、あるいはシグナルの強いコールド DM)とその理由。
  • アウトリーチのドラフト — 上位ペルソナ向けの短く具体的なメッセージ。あなたの実際の実証ポイントに基づきます。
  • ライブまたは手動 — 任意のキーで共有プロバイダーカスケードを通じてライブ実行するか、コピー&ペースト用のプロンプトを返します(正直なフォールバック、捏造なし)。プランを保存は完成したプランをユーザーレイヤー(networking/net-{company}-{role}-{date}.md)に永続化し、ページは保存済みプランの一覧・表示・削除を行います。

新規: server/lib/routes/networking.mjs(19 番目のルートモジュール)、public/js/views/networking.jsPATHS.networkingDir。v1.90.0 の server/lib/llm-dispatch.mjs カスケードを再利用します。16 ロケールすべてに 24 個の新規 i18n キー。テスト: tests/networking-routes.test.mjs

[1.90.0] — 2026-07-04

Mock Interview 2.0(Epic 15)。 新しい #/mock-interview ページは、あなたの CV・プロフィール・two-pager・ストーリーバンクをターン制の面接リハーサルに変えます:

  • 対話型の練習 — 目標とする職種(+任意で企業 / JD)を設定すると、面接官が的を絞った質問で始めます。送信した各回答には構造化された返答が返ります:Feedback(強み + STAR+R のギャップ)、Score(N/5)、そして直前の回答の最も弱い部分を突く Next question。サーバー側であなたの実際の資料に基づいており — 持っていない経験を捏造しません。
  • ストーリーバンク対応interview-prep/story-bank.md がプロンプトにインライン展開され(cv.md と同じ信頼レベル)、フィードバックがあなた自身の最良のストーリーを指し示せます。
  • ライブまたは手動 — プロバイダーキーがあれば、そのターンは共有プロバイダーカスケード(Anthropic → Gemini → OpenAI → Qwen → OpenRouter → GitHub Models)経由でライブ実行されます。キーがなければ、そのままコピー&ペーストできるプロンプトが得られます(誠実なフォールバック、捏造された回答なし)。
  • 保存されたセッションSave transcript をクリックすると、完了した面接がユーザーレイヤー(interview-prep/mock-{company}-{role}-{date}.md)に保存されます。ページ上で保存済みセッションを一覧表示・開く・削除できます。

新規: server/lib/routes/interview.mjs(18 番目のルートモジュール)、public/js/views/mock-interview.jsserver/lib/llm-dispatch.mjs(共有プロバイダーカスケード)、PATHS.storyBankbundleProjectContext({ extraFiles })16 ロケール 全体で 30 個の新しい i18n キー。テスト: tests/interview-routes.test.mjs

[1.89.0] — 2026-07-04

候補者と市場のフィット — two-pager(Epic 14)。 新しい #/two-pager ページで、次の職務に対して あなた自身 が本当に求めるものを書き留められます。Never Search Alone の「Mnookin two-pager」をモデルにしています:

  • ガイド付きビルダー — 一人称の「私は誰か」ナラティブ、「ターゲット環境」ノート、そして 5 つのチップリストエディタ: lovesmust-haveshatesdeal-breakersnon-negotiables。親プロジェクトのユーザーレイヤーconfig/two-pager.yml)に PUT /api/two-pager 経由で保存されます — システム更新で上書きされることはありません。
  • AI 入力アシスタントPOST /api/two-pager/draft)— あなたの CV + プロフィールをインライン化した、そのまま実行可能な Mnookin プロンプトを組み立てます。任意の LLM で実行し、結果を貼り戻してください。使うのはあなた自身の素材だけで、何も捏造しません。
  • 求めるものとの適合バッジ#/scan の各求人に ◎ N の適合スコア(クライアント側、window.FitScore 経由)が表示され、求人の勤務形態・国・最低給与・移転をあなたの two-pager と照合します。設計上、正直です: 求人が照合可能なシグナルを与えない場合、バッジは表示されません(捏造した数値は決して出しません)。deal-breaker 違反は軽い嫌悪より重く扱われます。
  • すべての評価に反映 — 保存された two-pager は bundleProjectContext にインライン化されるため、以降のすべての LLM 評価が、あなたが表明した好みと CV 対 JD のマッチングを合わせて考慮します。

新規: server/lib/routes/two-pager.mjspublic/js/views/two-pager.jspublic/js/lib/fit-score.jsPATHS.twoPager16 ロケールすべてに 27 個の新規 i18n キー。テスト: tests/two-pager-routes.test.mjstests/fit-score.test.mjs

[1.88.0] — 2026-07-04

Issue #29 の仕上げ — スキャンの i18n の抜け + API の衛生。

  • 最後まで残っていたハードコードのスキャン文字列をローカライズ(ロードマップ v1.69.4): ソース要約のピル(N 件の新規 / M 件の一致)、N 件の新規求人 トースト、reloc バッジが t() を経由するようになりました — 16 ロケールすべてに 4 つの新規キー(scan.pillNewscan.pillMatchingscan.newOffersscan.relocBadge)。英語以外のユーザーは、コアのスキャンフローで英語が紛れ込むのを見なくなりました。
  • X-Powered-By ヘッダーを無効化(ロードマップ v1.69.5): createApp() 内の app.disable('x-powered-by') — サーバーはもう Express を広告しません。(このエピックの残りはすでに出荷済み: parentVersion は release-please のコメントを除去、ライトモードのテーマ切り替え、ルート変更時のモーダル閉じ、レポートの「Score」(rep.score)のローカライズ。)

テスト: tests/scan-i18n-gaps.test.mjs + tests/security-headers.test.mjsX-Powered-By 不在アサーション。

[1.87.0] — 2026-07-04

認証不要のスキャンプロバイダーを4つ追加(親 career-ops v1.16.0 との同等性)。 スキャナーレジストリが 41 → 45 アダプター(40 EN + 5 RU)に増えました — すべて公開、認証なし、ホスト固定、redirect:'error'(SSRF セーフ)で、それぞれ CI 分離テスト付きです:

  • Get on Board (getonbrd) — ポータル全体の公開 JSON:API(LATAM/リモート技術)、プロバイダー選択、ページネーション対応。server/lib/sources/getonbrd.mjs
  • Amazon (amazon) — amazon.jobs の公開検索 JSON、ホスト検出または provider: amazon、オフセットページネーション。server/lib/sources/amazon.mjs
  • Avature (avature) — テナントごとの *.avature.net ATS、HTML 解析、ホスト検出または provider: avatureserver/lib/sources/avature.mjs
  • SAP SuccessFactors (successfactors) — テナントごとの RMK タイルリスト(*.successfactors.eu/.comjobs2web.com)、HTML 解析。server/lib/sources/successfactors.mjs

それぞれが sources/<slug>.mjs(自動検出される meta#/scan ドロップダウン)および ALL_ADAPTERS 内の portals/adapters/<slug>.mjs(2つのレジストリのルール)+ tests/sources-<slug>.test.mjs を同梱します。ALL_ADAPTERS の数とソート済み id・/api/scan/sources の EN セットのアサーションは 36→40 に増え、GET /api/scan/sources は現在 45 件を列挙します。

[1.86.0] — 2026-07-03

ターゲット職種別の統計(#/stats)— あなたのターゲット職種に対する市場の求人・給与統計。 新しい分析ページがプロフィールのターゲット職種config/profile.yml → ハードコードではない)と最新スキャンの求人を読み取り、職種と国ごとに次を表示します:

  • 国別の求人数国別の給与中央値(USD) — スキャナーがすでに収集している疎なデータからクライアント側で集計されます(public/js/lib/role-stats.jswindow.Countries を再利用)。任意通貨の給与は明示的に近似の FX テーブルで USD に正規化され、サンプルサイズに関する注意書きが添えられます — 決して捏造されません。
  • 職種・国フィルターと手書きのインライン SVG 棒グラフ・トレンドチャート(新規依存なし、CSP セーフ — addEventListener のみ)。
  • スナップショット保存POST /api/stats/snapshot)は現在の集計を data/role-stats.jsonl に永続化し、トレンドチャートGET /api/stats/trend)は時系列での求人数を追跡します — 「ダイナミクス」ビュー。誠実なハイブリッド: スナップショットはローカルのスキャンデータから生成され、オンデマンドで更新されます。
  • 16 ロケールすべてに完全ローカライズ(新規 i18n キー 26 個)。

新規: server/lib/routes/stats.mjs(16 番目のルートモジュール)、public/js/lib/role-stats.jspublic/js/views/stats.jsPATHS.roleStats;テスト role-stats.test.mjs(7)+ stats-routes.test.mjs(5)。

[1.85.0] — 2026-07-03

ドイツ語・イタリア語・トルコ語ロケール(親 career-ops v1.16.0 ロケールパリティ)。 UI が 16 言語で提供されるようになりました — 既存の 13 言語に de 🇩🇪、it 🇮🇹、tr 🇹🇷 が加わります。

  • UI 全体の翻訳public/js/lib/locales/i18n-dict.{de,it,tr}.js で 730 個の i18n キーをすべて翻訳。言語スイッチャーに Deutsch / Italiano / Türkçe が表示され、ブラウザ言語の自動検出が de/it/tr を認識します(public/js/lib/i18n.js)。
  • アプリ内ヘルプガイドdocs/help/{de,it,tr}.md を翻訳(完全な 19 H2 / 75 H3 構造)、GET /api/help/:lang で配信されます。
  • ドキュメントREADME.{de,it,tr}.mdCHANGELOG.{de,it,tr}.md を追加。CHANGELOG のロケールパリティゲートが 15 の非 EN ロケールをカバーするようになりました。
  • プロンプトのスキャフォールディングserver/lib/prompts.mjsLOCALE_NAMES + SCAFFOLD_STRINGS)を 3 つの新規ロケール向けにローカライズし、LLM の出力が UI 言語に従うようにしました。

すべてのパリティゲート(i18n-locale-filesi18n-coveragecheck-changelog-paritylang-switcher-rtl)を 16 ロケールセットに拡張しました。

[1.84.0] — 2026-06-30

再応募クールダウン + pipeline.md への報酬情報(親 career-ops v1.15.0 パリティ)。 スキャナーの 2 件のアップグレード:

  • 再応募クールダウン (#1201): EN スキャンが最近応募した企業の求人をスキップし、結果が新しい求人にフォーカスされます。config/profile.ymlre_apply_windows: 以下で企業ごとの期間を設定できます(last_apply_datesame_role_daysapplied_to: [roles]、省略可能な cross_role_bucket);企業マッチングは句読点非依存 + 単語境界(server/lib/cooldown.mjs)。キーが存在しない場合は無効;スキャンログに Cooldown skipped: N が表示されます。
  • pipeline.md への報酬情報 (#1017): スキャンされた求人が給与をオプションの末尾カラム(url | <salary>)として data/pipeline.md に保存されます。URL は重複排除キーのまま(| comp 列は読み込み時に除去)、セルはサニタイズされ(行/列インジェクションなし、数式先頭を無効化)、ベア URL のパイプラインは後方互換性を維持します。

tests/cooldown.test.mjs および pipeline 報酬テストを同梱。ソース数は 41 のまま — いずれもスキャンロジックのアップグレードであり、新しいボードではありません。

[1.83.0] — 2026-06-30

再掲載 / ゴースト求人検出器(親 career-ops v1.15.0 パリティ)。 #/scan に新しい 🔁 再掲載 / ゴースト求人 パネルが追加され、90 日のローリングウィンドウ内で異なる URL に再掲載された企業+職種クラスタを表示します — 古い採用パイプラインやゴースト求人のシグナルです。ファジー職種タイトルマッチャー(server/lib/role-matcher.mjs)と data/scan-history.tsv に対する読み取り専用の検出器(server/lib/detect-reposts.mjs)を基盤とし、GET /api/scan/reposts で公開されます。また:/api/healthparentVersion がセマバーのみを返すようになりました(リリース-プリーズ # x-release-please-version コメントを除去)。tests/detect-reposts.test.mjs を同梱。ソース数は 41 のまま — 再掲載は分析機能であり、新しいボードではありません。

[1.82.0] — 2026-06-30

NoDesk スキャンソース(親 career-ops v1.15.0 パリティ)。 ボード全体の NoDesk リモート求人 RSS フィードが第一級のスキャンソースになりました — provider: nodesk のエントリを追加すると #/scanSource ドロップダウンに表示されます(合計 41 アダプタ:EN 36 + RU 5)。ホストは nodesk.co に固定し redirect:'error'(SSRF 対策);タイトルは Role at Company で分割(NoDesk にはロケーションタグがないため所在地は空欄のまま);全行リモート。CI 隔離の tests/sources-nodesk.test.mjs スイートを同梱;フルユニットスイート 1523 件グリーン。

[1.81.0] — 2026-06-29

親 career-ops パリティ — 13 件の新規求人ボードスキャンソース。 Fighter90/career-ops main の最新プロバイダバッチをインプロセススキャナに移植します。ボード全体の公開 API(プロバイダ選択): ArbeitnowHimalayasJobicyLanding.jobs4 Day WeekThe MuseThe HubJobspresso(RSS)、Hacker News “Who is hiring?”(Algolia 2 ステップ)。ポーランドのボード(ホストまたは provider: 検出): JustJoin.it および NoFluffJobs(POST 検索)。テナント別 ATScareers_url から自動検出): Pinpoint<slug>.pinpointhq.com/postings.json)および Ripplingats.rippling.com/<slug>api.rippling.com ボード)。すべてのソースは redirect:'error' でホスト固定(SSRF 対策)され、#/scanSource ドロップダウンで選択できます — レジストリは 40 スキャナアダプタ(EN 35 + RU 5)を提供します。ソースごとの CI 隔離テストスイート 13 件を追加; フルユニットスイート 1513 件グリーン。

[1.80.0] — 2026-06-28

スキャンの 5 つの強化(job-crawler のアイデアを再実装)。 (1) Teamtailor ソース — <slug>.teamtailor.com のテナント別キャリアサイトを公開 /jobs.rss フィード経由で取得。careers_url から自動検出(ホスト固定 + redirect:'error')。レジストリは 27 アダプタ に。(2) ソースのクォランティン — 恒久的な 404/410 を返したソースを data/scan-quarantine.json に記録し、以後のスキャンでスキップ(自己修復:14 日後に再試行)。(3) ソースごとの上限#/scan の任意フィールドで各ボードの件数を制限(既定は ∞)。(4) 投稿期間 — クライアント側の経過フィルタ(24時間 / 7日 / 30日)。(5) 保存した検索 + ★ お気に入り — フィルタセットに名前を付けて再利用し、求人にスターを付与。localStorage に防御的バリデーション付きで保存(壊れたキャッシュはクリーンにリセット)。結果キャッシュはスキャン前にリセットされ、ライブで再充填されます。

[1.79.0] — 2026-06-28

WeWorkRemotely スキャンソース(親 career-ops v1.14.0 パリティ)。 We Work Remotely のボード全体のリモート求人 RSS フィードが第一級のスキャンソースになりました — provider: weworkremotely のエントリを追加すると #/scanSource ドロップダウンに表示されます(合計 26 アダプタ)。ホストは weworkremotely.com に固定し redirect:'error'(SSRF 対策)。タイトルは Company: Role で分割。さらに title_filter のキーワードは長さチェックの前にトリムされます(parent #1261)。

[1.78.2] — 2026-06-27

i18n と UX の強化(v1.78.1 のフォローアップ)。 ロゴのアクセシブル名が 13 言語すべてでローカライズされました(nav.logoHome)。すでに #/scan にいる状態でのグローバル検索 Enter は強制再レンダーし、入力済みの語が失われません(同一ルートガード)。health.title がポーランド語(Kondycja)とデンマーク語(Systemtilstand)に翻訳されました(以前は英語のまま)。テスト 1235 → 1238。

[1.78.1] — 2026-06-27

Scan の UX 修正。 #/scan の結果テーブルが、スキャン中もライブで自動更新され、完了後にもう一度更新されます(手動リロード不要)。トップバーのグローバル検索は Enter ヒントを表示し、URL でないクエリでは検索欄を埋めた状態で #/scan へ遷移します(以前は #/tracker)。ロゴはダッシュボード(ホーム)へのリンクになりました。

[1.78.0] — 2026-06-27

Scan ページに地域フィルター — 国ごと(国旗付き)に求人を絞り込み。 #/scan の新しい ドロップダウンは、結果から検出した各国(国旗絵文字+件数)を一覧表示し、特定の国に紐づく求人だけに絞れます。Remote/Hybrid/Onsite の勤務形態フィルターと併用でき、国に紐づく仕事もリモートも探せます。新しい countries.js ヘルパーが求人のフリーテキストの所在地(国名・別名・約100の主要都市)を ISO 国コード+国旗にマッピング。検出は保守的で、決して推測しません。

[1.77.0] — 2026-06-27

デンマーク語 (Dansk) を 13 番目の UI 言語として追加。 UI、アプリ内ヘルプガイド(19 H2 / 75 H3)、README、CHANGELOG をデンマーク語に完全翻訳。デンマーク語は国旗付き言語ピッカーに追加され、i18n の仕組み(アセンブラ、監査、パリティゲート、スナップショット)は 13 ロケールに対応しました。

[1.76.0] — 2026-06-26

親 career-ops v1.13.0 とのパリティ — 新規ソース6件、スキャナ堅牢化、結果テーブルの上限撤廃。

追加

  • テナント別ATSソース6件 — BambooHR、Breezy HR、Comeet、Personio、Recruitee、SolidJobs。careers_url のホストから自動検出(Comeet は完全な api: が必要)。各ホストはアンカー付き正規表現 + redirect:'error' で固定(SSRF対策)。#/scanSource ドロップダウンで選択可能 — レジストリは 25 アダプタ(EN 20 + RU 5)に。Personio の XML フィード用に fetchText ヘルパーを追加。
  • trust_filter — 任意の信頼スコア(0–100、レベル high/medium/low、フラグ)。注釈のみ。high 未満の行は #/scan に言語非依存の ⚠ バッジを表示。求人は決して除外しない。
  • Arbeitsagentur remoteMatch + remoteMaxPages — 設定駆動のリモート判定:titlefilter(サーバー側 homeoffice=nv_true + ページング)、off

変更

  • スキャン結果の上限なし。 表示上限 MAX_STORED_RESULTS(2000)を撤廃 — 一致した求人をすべて保存し、#/scan テーブルでページ送り(200件/ページ)。
  • タイトルフィルタの堅牢化 — 短い略語(COO、SDR…)は単語境界で一致;不正な title_filter 設定でスキャンが落ちない。ATS と地域スキャナの両方。

テスト

  • +32 ケース(1190 → 1222):sources-ats-providerstitle-filterarbeitsagentur-remotetrust-validator、書き直した scan-result-cap「上限なし」ガード。

[1.75.2] — 2026-06-19

docs: v1.75.0 のスキャナ集約サイトに対する全12ロケールでの完全なドキュメントパリティ。 コード変更なし — v1.75.0 で着地した7件のソースにユーザー向けドキュメントを揃えます:

  • ヘルプガイド(12ロケール)。 §5 に content_filter ブロック(説明/スニペットのキーワードゲーティング、location_filter の兄弟)と集約サイトに関するノートが追加されます。§7 はワンクリックスキャンの一巡と Source ドロップダウンの完全な列挙に7件の新規ソースを記載します。§17 のアダプタ数が古い “11 adapters” から “19 adapters — 14 English + 5 Russian” へ訂正されます。##/### の見出しは追加していないため、ゲートされた 19 H2 / 75 H3 構造は変更されません。
  • README(9件の完全ロケール)。 スキャンソースの下に新しい “Aggregator boards (v1.75.0)” の箇条書きが追加され、リリースバッジが v1.75.2 に更新されます。(省略版の pl/uk/ar README にはソースごとのリストがなく、その箇所は意図的に手を付けていません。)
  • リファレンスドキュメント。 docs/portals-examples.md に7件すべての正確な provider: / <provider>: 設定ブロックを備えたコピー&ペースト用 “Aggregator boards” セクションが追加されます。docs/PROJECT.md19 adapters に更新されます。docs/sdd/CONVENTIONS.md は、2つのレジストリの区別(ドロップダウン用 sources/registry.mjs 対フェッチ用 portals/registry.mjs)、opts.company として通される provider: ベースの集約サイト選択、スキャン書き込みのサニタイザ(scan-sanitize.mjs)、および v1.75.1 のテスト数(1190)を文書化します。
  • QA。 qa/QA-REGRESSION-PROMPT-v1.75.2-FULL.md を追加 — v1.75.x のスキャン集約サイトサイクル向けに刷新した、全面的なリリースゲートドライバ。

[1.75.1] — 2026-06-19

fix(scan): v1.75.0 の構成駆動ソースに対する堅牢性の仕上げ。 リリース後レビューから得られた 3 つの小さな強化修正です(正常なスキャンでは動作変更なし):

  • Abort を考慮したページネーション遅延。 Glints(300 ms)および Jobstreet/SEEK(200 ms)のページ間の待機は、server/lib/http-json.mjs の新しい delay(ms, signal) ヘルパーを介して、スキャンの AbortSignal が発火すると即座に解決されるようになりました。これにより、切断されたクライアントがページネーション中のスキャンを余分な待機分だけ占有し続けることができなくなります。
  • 説明的な非 JSON エラー。 fetchJson は、非 JSON の 2xx ボディ(例: ステータス 200 で配信される HTML メンテナンスページ)を、むき出しの SyntaxError を表面化させる代わりに non-JSON 2xx response from <url> としてラップするようになりました。これにより、スキャナーのソースごとのエラーログが不正な挙動のエンドポイントを明示します。
  • より強力なスキャン書き込みの正規化。 normalizeScanScalar は、\r \n \t に加えて、垂直タブ、フォームフィード、および Unicode の行/段落区切り(\v \f U+2028 U+2029)も折りたたむようになりました — 厳密な上位集合であり、スプレッドシートやビューアが尊重しうるレコード/行区切りが scan-history.tsv に生き残ることはありません。

[1.75.0] — 2026-06-19

feat(scan): 親 career-ops v1.12.0 のパリティを移植 — 新規求人ソース7件、コンテンツフィルタリング、セキュリティ/品質修正。 web-ui は独自のインプロセススキャナを実行し(親の scan.mjs へシェルアウトしない)、そのため親 v1.12.0 のプロバイダおよびスキャン変更は自動的には流れ込みません — 本リリースでは、適用可能なものを web-ui のアダプタ契約に沿って再実装します。

  • 新規スキャナソース7件。 ボード横断のリモート集約サイト3件 — RemoteOKRemotiveWorking Nomads — は自動検出される server/lib/sources/*.mjs パターンに収まります(provider: remoteok / remotive / workingnomads で選択)。設定駆動の地域集約サイト4件 — IBM careers、Arbeitsagentur(ドイツ連邦雇用庁)、Glints(東南アジア)、Jobstreet / SEEK — はエントリごとの <provider>: 設定ブロックを読み取ります。en-scanner は解決済みの企業エントリを各フェッチャーまで通すようになり、フェッチャーがそれを読めるようになりました。7件すべてが #/scan のソースドロップダウンに自動的に表示されます。
  • content_filter(親 #974)。 求人をその説明/スニペットのテキストでゲートする任意の portals.yml ブロック(positive / negative キーワードリスト) — location_filter のセマンティクスを踏襲し、説明のない求人は常に通過します。EN と RU の両スキャナに組み込まれました。
  • スキャン書き込みの堅牢化(親 #1098)。 外部フィードのメタデータは data/scan-history.tsv および data/pipeline.md に書き込まれる前にサニタイズされるようになりました: 制御文字は折りたたまれ(企業名/タイトルの改行が TSV 行を注入できなくなりました)、先頭の = + - @ はスプレッドシートの数式インジェクションに対して無効化されます。
  • Ashby secondaryLocations(親 #1073)。 Ashby ソースは各セカンダリロケーションの地域ラベルに加えて郵便の addressLocality / addressCountry をロケーション文字列に畳み込む(重複排除)ようになり、主ラベルが例えば “Canada” と表示される EU 対象の職務が location_filter で表面化します。
  • 評価レポート形状の検証(親 #819)。 /api/evaluate のインプロセスプロバイダ(Anthropic / OpenAI / Qwen / OpenRouter / GitHub Models)は、不正な形式の A–G / SCORE_SUMMARY レポートを致命的でない warnings 配列としてフラグするようになりました。Gemini 評価パスは親の gemini-eval.mjs から既にこのガードを継承しています。
  • docs: Antigravity CLI を12のすべての README のサポート対象アシスタント一覧に追加(Gemini プロバイダにマッピング)。

親の git pull から無償で継承(web-ui はこれらへシェルアウトします): 日本語 CJK PDF フォントのフォールバック(#1053)、ATS セーフな PDF フォント(#1074)、LaTeX CJK ガード(#1054)、tracker/merge/followup/dashboard の修正、および modes/zh 中国語モード(web-ui はモードを動的に列挙します)。


[1.74.3] — 2026-06-18

docs(parent-source): 親 career-ops リポジトリを Fighter90/career-ops フォークに向ける。 web-ui は実際のソースとして使われるすべての箇所でメンテナーのフォークを親プロジェクトとして参照するようになりました: bin/setup.sh インストーラーの CAREER_OPS_REPO クローン既定値、12 個の README にあるすべての git clone /「の上に乗る」/ オンボーディングリンク、そしてエージェントドキュメント(CLAUDE.mdAGENTS.mdGEMINI.md.github/copilot-instructions.mddocs/)。作者 santifer へのクレジット(および非公式 UI の免責表示)は変更なし — ソース/クローン URL のみ移動しました。tests/sh-files.test.mjs はインストーラーがフォークをクローンすることを検証するようになりました。


[1.74.2] — 2026-06-17

fix(health): #/health/api/status/providersGITHUB_MODELS_API_KEY をオプションのチェック項目として表示。 v1.74.0 の GitHub Models プロバイダーは #/config で設定可能でしたが、Health ページに行がなく、keysConfigured プロバイダーサーフェスからも欠落していました。オプションのチェック項目(他の5つのライブ評価プロバイダーと同じ “set / unset (manual mode)” の文言)と github(+ その GITHUB_MODELS_MODEL)を /api/status/providers に追加したため、アクティブプロバイダーのルーティングと Health ページが6つすべてを反映するようになりました。tests/api.test.mjs のヘルス行テストを6つのプロバイダーすべてに拡張しました。


[1.74.1] — 2026-06-17

docs + test: README の「AI アシスタントをインストールする」セクション;Gemini コネクタの完全ブランチカバレッジ。 README にインストール/ログイン一覧表を追加 — Claude Code / Gemini CLI / Codex / Qwen Code / OpenCode / GitHub Copilot CLI のインストールリンク + それぞれの #/config プロバイダーマッピング + 「続行前にログインしてください」(career-ops.org/docs のクイックスタートを反映;web-ui が CLI 不要のスタンドアロン代替手段であることを明確化)。新しい tests/gemini-connector.test.mjs(8 ケース)は runGemini のすべてのブランチをカバー — キーなし、成功、API エラー、空/ブロックされた補完、不正な形式のボディ、タイムアウト、ネットワークエラー、hasGeminiKeyserver/lib/gemini.mjs のステートメントを 100% に到達させる。全体カバレッジ: 96% ライン / 88% ブランチ / 96% 関数。スイート 1126 → 1134。


[1.74.0] — 2026-06-17

feat(llm): GitHub Models (Copilot) を第6のプロバイダーとして追加 + 6アシスタントの標準的な整列. career-ops.org/docs には、6つのAIコーディングアシスタントが記載されています — Claude Code, Gemini CLI, Codex, Qwen Code, OpenCode, GitHub Copilot CLI。web-ui はこれら6つすべてをサポートするようになりました: 5つは既存のライブプロバイダー (Anthropic / Gemini / OpenAI / Qwen / OpenRouter) に対応し、GitHub Copilot CLI は専用の GitHub Models コネクター — runGitHubModels (OpenAI-compatible; models スコープを持つ GitHub PAT) を獲得します。これは #/config (GITHUB_MODELS_API_KEY + GITHUB_MODELS_MODEL) で設定可能で、LLM_PROVIDER=github で選択でき、auto 順序では6番目です。ヘルプバンドルと README は標準の6つをリストするようになり (Qwen CLI→Qwen Code に改名; Gemini CLI + GitHub Copilot CLI を追加)、README にはすべての機能が親プロジェクトに追跡できるよう、完全なモード参照とポータルアダプターのリンクテーブルが career-ops.org/docs に追加されます。tests/llm-provider-context.test.mjs はフェッチ境界マトリックスを6つのプロバイダーすべてに拡張し (cv.md + profile.yml インライン + アーティファクト返却)、新しい GITHUB_MODELS_* キーがすべての12のロケール辞書に追加されます。スイート 1125 → 1126。


[1.73.0] — 2026-06-17

feat(llm): 汎用Geminiコネクター + 全プロバイダーにわたって検証済みのCV/プロフィールコンテキスト。 server/lib/gemini.mjs (runGemini) を追加しました — Anthropic / OpenAI互換クライアントと同じ {markdown, usage, error} の形式を返す、外部依存なしのGemini generateContent クライアントです。修正: /api/mode/:slug/api/deep はこれまで、オファー評価専用の gemini-eval.mjs を通じてプロンプトを処理していたため、Gemini Run live が要求されたアーティファクト(カバーレター、アウトリーチ、ブリーフ)の代わりに評価を返していました。現在は bundleProjectContext とともに runGemini を呼び出すため、他のすべてのプロバイダーと同様に cv.md + config/profile.yml がGeminiにもインラインで埋め込まれ、レターやブリーフが詳細かつパーソナライズされます。新しい tests/llm-provider-context.test.mjs は各プロバイダーのHTTP境界をモックし、5つのプロバイダー(Anthropic / Gemini / OpenAI / Qwen / OpenRouter)すべてが cv.md + profile.yml をインラインで埋め込み、アーティファクトを返すことを検証します(mode + deep + evaluate マトリックス、9ケース)。/api/evaluate はオファー専用の gemini-eval.mjs を維持します。Suite 1116 → 1125。


[1.72.0] — 2026-06-17

feat(modes): Run live が最終成果物を直接返すようになりました(シングルショット出力コントラクト)。 親テンプレート modes/<slug>.md はClaude Codeのインタラクティブセッション向けに書かれており、いくつか(cover、contactoなど)は結果を生成する前に確認の質問のために一時停止します。これにより、WebUIの Run live が成果物ではなくアンケートを出力していました。buildModePrompt は現在、すべてのモードを非インタラクティブな出力コントラクトでラップします: 分析(JD分析、企業ノート、ATSキーワード、プロフィール↔JDのギャップ、トーン/アングルの選択)をサイレントに実行し、テンプレートが通常尋ねるものについては cv.md / config/profile.yml から適切なデフォルト値を選択し、最終成果物のみを出力します — モードごとの «output ONLY {the cover letter / outreach message / …}» リマインダーで締めくくられます。これにより、#/coverRun live をクリックするとカバーレター自体が返されます。同じ修正がすべての汎用モード(cover、contacto、interview-prep、project、training、followup、patterns)の12ロケール全体に適用されます(成果物はロケールディレクティブによりUI言語で記述されます)。Suite 1103 → 1116。


[1.71.2] — 2026-06-17

docs(i18n): ドキュメント整合性パスを公開します。各 README の “Translations of this guide” ブロックに、11 のサポート言語がすべて列挙されるようになりました(以前は English/Français が省略されたり自己リンクになっていたものがありました)。また、セクション区切り前の空行が復元されました。QA リグレッション プロンプト全体が現在のバージョン名に変更され、ドキュメント(CLAUDE.mdCONVENTIONSLOCALIZATIONPROJECT-CONTEXT)が現在のバージョンとテスト数(1103)に同期されました。コードや動作の変更はありません — ドキュメントのみの変更のため、ヘルプ/UI の翻訳および 1.70.0–1.71.1 のすべての機能は変更されていません。


[1.71.1] — 2026-06-17

fix(i18n): アプリ内ヘルプガイドが全12言語で完全に翻訳されました。 docs/help/{pl,uk,ar}.md を追加し(それぞれゲート済みの 19 H2 / 75 H3 構造を含む)、#/help が英語へのフォールバックではなくポーランド語・ウクライナ語・アラビア語のネイティブバンドルを提供するようになりました — GET /api/help/{pl,uk,ar} がそれぞれのロケールを返すようになりました。すべてのヘルプゲート(help-ui, help.test, help-ru-config-section, canonical-docs-coverage)に接続されています。また、12言語すべての翻訳リストを完成させました: READMEの «Translations of this guide» ブロック(9つのREADME)、ローカライズされたCHANGELOGの «Translations:» ヘッダー(8ファイル)、そして古くなったドキュメントの数値を更新しました。Suite 1100 → 1103.


[1.71.0] — 2026-06-16

feat(cover): #/cover から直接カバーレターPDFを生成します。 v1.70.0で追加されたcoverモードはレター本文を生成します。結果画面に Generate PDF ボタンが追加され、共有インラインmarkdown→PDFパイプライン(POST /api/stream/pdf/inlinegenerate-pdf.mjs)を通じてレンダリングされます。これはinterview-prepが使用するのと同じパスです。SPA を離れることなく、レターを作成してPDFを送付できるようになりました。

test/docs: v1.70.0 レビューの堅牢化。 coverモード(許可リスト+プロンプト組み立て)、国旗 <select> スイッチャー+アラビア語RTL(dirFor/<html dir>)、すべてのロケールの top.langLabel、カバーレターPDFの配線、prompts.mjs ロケールディレクティブ+fr/pl/uk/ar のスキャフォールディングについて、CI 分離カバレッジを追加しました。docs/sdd/CONVENTIONS.md および全プロジェクトQAリグレッションプロンプトの古い「全8件」→12ロケール参照を更新しました。


[1.70.0] — 2026-06-16

feat(i18n): 新しいUIの言語として、ポーランド語(pl)、ウクライナ語(uk)、アラビア語(ar、完全なRTL対応)の3言語を追加し、SPAを12ロケールに拡張しました。これは親プロジェクト career-ops の READMEに記載されたすべての言語と一致します。 各新ロケールには697キーの完全な辞書(public/js/lib/locales/i18n-dict.{pl,uk,ar}.js)が含まれており、既存のパリティ / カバレッジ / ラテン文字漏れなし / 個人データなしのテストスイートで検証されています。アラビア語は本格的な右から左へのサポートを追加します: i18n.js はRTLロケールに対して <html dir="rtl"> を設定し、app.css のスコープ付き [dir="rtl"] ブロックはクロム(サイドバー、通知ドロワー、マークダウンテーブル/ブロック引用、インライン間隔)をミラーリングします — LTRロケールはバイト単位で変更されません。新しい top.langLabel キー(×12)がスクリーンリーダー向けにピッカーを命名します。

feat(ui): フラグアイコン付き <select> 言語切り替えが折り返しボタン行を置き換えます。 12ロケールでは、旧来の .lang-btn 行がサイドバーで3行に折り返されていました。ネイティブの <select>(各オプションに国旗絵文字のプレフィックス)はすっきりとスケールし、キーボードおよびスクリーンリーダーに対応しており、CSPに安全です(addEventListener を介した変更ハンドラー、インラインJSなし)。プラットフォームに国旗グリフがない場合は地域文字に降格されるため、言語ラベルが常に主要な識別子となります。

feat(cover): 親プロジェクトのカバーレターモード(career-ops v1.10.0 + v1.11.0 の挨拶文)をSPAに移植します。 汎用モードランナーを基盤として、アプリケーションナビグループの下に新しい #/cover ページを追加: 求人説明 + 企業名/職種 + オプションの挨拶文 → cv.md / modes/_profile.md から生成されたカスタマイズされたレター。サーバーの MODE_ALLOWLISTcover を追加し、cover.* i18nブロック(×12ロケール)を追加しました。

chore(compat): 親プロジェクト career-ops v1.11.0 を追跡します。 読み取り/書き込みコントラクトが維持されていることを確認しました — data/applications.md は引き続きMarkdownの信頼できる情報源です(v1.11.0のSQLiteトラッカーインデックスは派生キャッシュ)。トラッカーの列は引き続きヘッダーマッピングされています。parentVersion は1.11.0を報告するようになりました。

fix(i18n): フランス語(v1.61.0で追加)が server/lib/prompts.mjsLOCALE_NAMES および SCAFFOLD_STRINGS に欠落していた潜在的な問題を修正しました — フランス語のLLM呼び出しは暗黙的に英語出力と英語スキャフォールディングにフォールバックしていました。fr/pl/uk/ar がすべてプロンプトロケールパスに接続されました。

既知のフォローアップ: アプリ内ヘルプガイド(docs/help/)はpl/uk/arでは英語にフォールバックします(UIクローム自体は完全にローカライズ済み)。親プロジェクトのインタラクティブなインタビューオンボーディング、リバースATS探索、新しいスキャンプロバイダーはまだSPAに公開されていません。


[1.69.2] — 2026-06-12

fix(test): npm test が実際の config/profile.ymldata/scan-history.tsv を上書きしてしまうテスト分離リークを修正。 tests/critical-fixes.test.mjs がファイル冒頭で prompts.mjs(→ paths.mjs)を読み込んでいたため、before()CAREER_OPS_ROOT を一時ディレクトリに設定する前に PROJECT_ROOT が実際の親に解決され、PUT /api/profile が毎回「Acceptance Test」フィクスチャを実際のプロフィールに書き込んでいました。修正:prompts.mjsbefore() 内で動的 import() により読み込むように変更。新規 tests/test-root-isolation.test.mjs(2 ケース)がスイート全体をこのパターンから保護します。本番コードの変更なし。スイート 1084 → 1086。


[1.69.1] — 2026-06-12

fix(scan): #/scan が大規模な地域スイープを黙って切り詰めなくなりました。 リージョンごとの表示セットが 500 件に固定されていました(実際の RU スキャンでは一致 1352 件のうち 500 件しか表示されず、852 件が非表示 =「2000 件スキャン、約 600 件表示」の症状)。両スキャナーは共有かつ環境変数で上書き可能な定数 MAX_STORED_RESULTS(既定 2000、SCAN_MAX_RESULTS で上書き)を使用します。表示のみ — pipeline.md / scan-history.tsv への追加は元から切り詰めなしのセットを使用していました。fix(health/ui): #/health のチェックカードがはみ出さなくなりました。 長い名前/値が Fix → ボタンとステータスバッジに衝突していましたが、.health-check-row で縮小・折り返しするようになりました。新規テスト scan-result-caphealth-card-overflow。スイート 1079 → 1084。


[1.69.0] — 2026-06-12

feat(scan): スキャナーアダプターの自動検出(P-14)— server/lib/sources/.mjs ファイルを置くだけで新しいソースを登録できます。 v1.69 以前は server/lib/sources/registry.mjs のソース一覧が手作業の静的配列で、アダプターを追加するには <id>.mjsregistry.mjs の両方を編集する必要がありました。これでロードマップ項目 P-14(docs/ROADMAP.md)の残作業を解消します。server/lib/sources/ 内の各 *.mjs はモジュール起動時に動的にロードされ、各アダプターは自己記述的なブロック export const meta = { value, label, region, configKey? } で自身を宣言します。同梱の 12 個のアダプター(ashby / greenhouse / lever / rss / smartrecruiters / workable / workday + geekjob / getmatch / habr / hh / trudvsem)に meta を追加。registry.mjsreaddirSync + 動的 import() を top-level await で解決します(Node 18+ の ESM 標準)。公開 API(SOURCES, SOURCES_BY_REGION, RU_CONFIG_KEYS, getRegionalSources)は変更なし — 既存のインポートはそのまま動作します。meta が不正な場合はスキップし、ファイルごとに console.warn を 1 回出力します。tests/sources-registry-discovery.test.mjs に 14 ケースを追加。スイート 1065 → 1079。


[1.68.2] — 2026-06-07

fix(bin): npx / npm link 経由の CLI 動詞が壊れていた — bin パスをシンボリックリンク経由で解決するよう修正。 npm と npx は career-ops-uinode_modules/.bin/ 配下のシンボリックリンクとして公開しますが、従来の dirname "${BASH_SOURCE[0]}" はパッケージのルートではなく .bin を指していたため、npx career-ops-ui initnode node_modules/scripts/init.mjs を実行して MODULE_NOT_FOUND で落ちていました(ローカルの npm install 実行は影響を受けず、バグが隠れていました)。bin/career-ops-ui.shbin/start.sh はシンボリックリンクのチェーンをたどって SCRIPT_DIR を正規化するようになり(readlink ループ + cd -P)、すべての動詞がリポジトリから、npm link 経由、npx 経由で動作します。.bin スタイルのシンボリックリンク経由で動詞を実行する回帰ロックを tests/sh-files.test.mjs に追加。スイート 1065/1065。


[1.68.1] — 2026-05-29

fix(scan): ソース別フェッチのタイムアウトを 10s → 60s に延長。 v1.67.1 の 10s fail-fast は、もう少し時間が必要なだけの「遅いが生きている」Ashby ボードも切ってしまっていました。デフォルトを 1 分に上げて、それらが返るようにします。トレードオフ: 本当に死んだ/ハングしたソースは 60s 丸ごと並列枠を占有し(最悪ケースのスキャンが遅くなる)、慢性的なハング(Perplexity・Supabase・Resend など)はおそらく依然としてタイムアウトします — 適切に直すならソース別 / Ashby の並列度を下げる対応が必要です。SCAN_FETCH_TIMEOUT_MS で上書き可。スイート 1063/1063。


[1.68.0] — 2026-05-29

feat(scan): 結果フィルタのパネルを刷新 — ラベル付きフィールド、適用ボタン、オフィス勤務オプション、そして機能する給与フィルタ。 #/scan の各フィルタはラベル付きフィールドになりました(プレースホルダーではなくコントロールのにラベル): 検索 · 勤務形態 · 給与 下限 · 給与 上限 · ソース · 範囲。明示的な適用ボタン(およびリセット、各フィールドでの Enter)でフィルタを再実行し、ページ上のヒントで使い方を説明します。給与レンジが実際にフィルタするようになりました — 下限/上限を設定すると、給与がレンジ外の求人および給与未掲載の求人は除外されます(レンジの重なり判定、通貨は無視)。勤務形態フィルタに、リモート / ハイブリッド / 転居 と並んでオフィス勤務オプションを追加。新規 i18n キー ×9、salaryInRange を厳格化、スイート 1063/1063。


[1.67.1] — 2026-05-29

fix(scan): ソース別フェッチのタイムアウトを 30s → 10s に短縮(fail-fast)。 v1.67.0 の 30s への引き上げでは遅い Ashby ボードの半分ほどしか復活せず、残り(Perplexity・Supabase・Resend・DeepL・Ramp など)は期限に関係なくハングするため、長いタイムアウトは死んだ枠を待ってスキャン全体を停滞させるだけでした。10s は慢性的なハングに即座に失敗し、スキャンの応答性を保ちます。SCAN_FETCH_TIMEOUT_MS で上書き可。スイート 1060/1060。


[1.67.0] — 2026-05-29

feat(scan): #/scan に給与レンジ(下限/上限)フィルタを追加し、ソース別フェッチのタイムアウトを延長。 結果テーブルに、テキスト・リモートのフィルタの隣に2つの数値入力(給与 下限上限)が加わりました。各行のフリーテキスト給与(от 100 000 до 200 000 ₽120000-150000 USD$120K–$150K など)を数値レンジに解析し、レンジの重なり判定でマッチします。給与未掲載の行は残すため、フィルタは一覧を絞り込むだけでゼロにはしません(通貨は区別しません=為替換算なし)。さらに ソース別スキャンのフェッチタイムアウトを 15s → 30s に延長SCAN_FETCH_TIMEOUT_MS で上書き可)。Ashby の includeCompensation ペイロードは ×8 並列下で >15s を要することが多く、毎回 ~30 の Ashby ボードがタイムアウトしていました。新規 window.Skills.parseSalaryRangesalaryInRange + i18n ×9、テスト13件追加、スイート 1060/1060。


[1.66.0] — 2026-05-28

feat(scan): RU ソースが最初のページだけでなく全ページを走査します。 hh.ru・Habr Career・Trudvsem はクエリごとに先頭 ~50 件しか取得していませんでしたが、最後までページを辿るようになりました — hh.ru/Habr は &page=N、Trudvsem は offset/meta.total — ページ間で重複除去し、新規が無くなったら(または 50 ページの安全上限で)停止します。「Backend разработчик」のようなクエリが 1 ページではなく全件を返します(例: hh.ru PHP 17 → 3 ページで 55 件以上、Trudvsem は 72 件すべて)。ページ単位のフェッチは既存のタイムアウト + AbortSignal を維持。テスト 4 件追加、スイート 1045/1045。


[1.65.0] — 2026-05-28

feat(scan): hh.ru を JSON API ではなく公開ウェブサイトからスクレイプ — どの IP からでもプロキシ不要で動作。 api.hh.ru は IP や User-Agent に関係なくすべてのプログラムクライアントに 403 forbidden を返すようになりました(エッジのアンチボット遮断)。一方サイト(hh.ru/search/vacancy)はブラウザ風クライアントに完全な結果を返すため、アダプタはその HTML を解析します(Habr Career と同様)。1.64.0 の HH_PROXY 変数と undici 依存を削除 — プロキシ・キー・User-Agent の設定は不要です。HTML パーサ向けにテストを書き直し、スイート 1041/1041。


[1.64.0] — 2026-05-27

feat(scan): HH_PROXY で hh.ru リクエストをロシアのプロキシ経由に. hh.ru は API を User-Agent ではなく IP でブロックするため、HH_USER_AGENT だけでは非ロシアの出口ノードからの 403 を解除できませんでした。HH_PROXY にロシアの HTTP/HTTPS プロキシ URL(例: http://user:pass@ru-host:port)を設定すると、hh.ru へのリクエストのみそのプロキシを経由し、他のソースは直接接続を維持します。undiciProxyAgent を利用(ランタイム依存を追加)。HH_PROXY 未設定時は dispatcher を一切付与しません。テスト3件追加、スイート 1041/1041。


[1.63.2] — 2026-05-27

feat(scan): #/scan コンソールにライブ % 進捗 + ソース別の詳細。 進捗バーが確定的になりました — スキャナーが進捗イベント(EN: 企業ごと、RU: クエリごと)を SSE で送出し、「Scanning… NN%」 ラベル付きでバーが満ちます(アニメ縞は最初のイベントまで)。各ソースの最初の失敗(タイムアウト / 403 / ネットワーク)はコンソールに詳細出力され、以降の繰り返しは抑制されます。新規テスト 1 件、スイート 1040/1040。


[1.63.1] — 2026-05-27

style(scan): #/scan の進捗バーをより目立つように。 実行中インジケーターに見える 「Scanning…」 ラベルを付け、バーを 8px(細い 4px から)に拡大。スキャン中にはっきり見えます。挙動の変更なし。


[1.63.0] — 2026-05-27

feat(scan): リクエストごとのタイムアウト + #/scan の進捗バー。 ソースのリクエストに期限がなく、停止した upstream(例:ブロックされた IP からの api.hh.ru)がスキャン全体をハングさせる可能性がありました。新しい server/lib/fetch-timeout.mjs がスキャナーの fetchImpl をラップし(makeTimeoutFetch、デフォルト 15秒SCAN_FETCH_TIMEOUT_MS で変更可)、各リクエストに厳格な期限を設定。タイムアウトしたソースは非致命的エラーとして記録され、スキャンは継続します。#/scan はスキャン中に進捗バーを表示(全 9 ロケールの scan.progress)。新規テスト 7 件、スイート 1039/1039。


[1.62.3] — 2026-05-27

docs: インストールを明確化(career-ops-ui は career-ops/web-ui/ の中で動作)+ init のトラブルシューティング、全 9 ロケール。 インストール節を Option 1(ワンライナー curl)/ Option 2(既存の career-ops プロジェクト内に web-ui として UI をクローン)+ CLI コマンド + プロバイダー設定 + Troubleshooting init ブロックに書き換え。ネスト構成の注記を /help §1 Setup にも追加し、README ハイライトで v1.62.* ライン全体を要約。ドキュメントのみ、コード変更なし。


[1.62.2] — 2026-05-27

fix(help): #/help のフィルターが全文検索になりました(RSS のような H3 サブセクションも見つかります)。 ヘルプページの検索/TOC フィルターは以前 H2 セクションタイトルのみに一致していたため、v1.62.x の RSS ドキュメント(§5 Portals & sources 配下の H3)が見つかりませんでした。各セクションの本文がフィルターにインデックスされるようになり、例えば「RSS」で検索すると §5 が表示されます。クライアント側のみ、API 変更なし。


[1.62.1] — 2026-05-27

feat(scan): ソースフィルターに RSS 追加 + RSS のロケーション修正。 #/scan のソースフィルターのドロップダウンに RSS が表示されるようになりました(server/lib/sources/registry.mjs と SPA のフォールバックリストに追加)。これにより RSS ボード(LaraJobs、WeWorkRemotely など)の結果も他の ATS ソースと同様にフィルターできます。RSS アダプターはフィードの <category> タグを location に割り当てなくなりました — 非ロケーションのタグが location_filter にリモート職を誤って除外させていたためです。現在 location は空になり、フィードはロケーションフィルターを通過します。スキャンボタンのツールチップ/ラベルとソース一覧の i18n 文字列を全 9 ロケールで更新(Workable / SmartRecruiters / Workday / RSS)。i18n スナップショットとソースエンドポイントのテスト(EN 6 → 7)を更新。


[1.62.0] — 2026-05-27

feat(scan): 非ATS求人ボード向けの汎用RSSアダプター。 新しい rss アダプター(server/lib/portals/adapters/rss.mjs + server/lib/sources/rss.mjs)により、スキャナーは任意のRSSフィード(LaraJobs、WeWorkRemotely、RemoteOK、golangprojects など Greenhouse/Ashby/Lever 以外のボード)から求人を取得できます。新しい依存関係なし:フィード解析は正規表現ベースで、CDATA と HTML エンティティに対応(タイトル/会社名はタグ除去、astral コードポイントは安全にデコード)。portals.ymlprovider: rss / rss: / feed_url: で企業ごとに有効化され、ATS で一致済みの企業を横取りしません。ALL_ADAPTERS は 6 → 7 に増加。29 件の新規テスト。9 つの README ロケールに記載。


[1.61.1] — 2026-05-22

fix(i18n): テーマトグルの title + aria-label を全 9 ロケールでローカライズ (MINOR-001)。 ダーク/ライトのテーマボタン(#theme-toggle)が index.htmltitle="Toggle theme"aria-label="Toggle theme" をハードコードしており — どのロケールでもツールチップとスクリーンリーダーのテキストが翻訳されませんでした。新しい top.themeToggle キー + applyI18n()data-i18n-title ハンドラ(v1.58.15 の検索 aria-label 修正と同じパターン)が、起動時と言語切替のたびに両属性をローカライズします。tests/playwright-theme-toggle-i18n.mjs(9 ロケール + ランタイム切替)と 2 つの静的ガードでロック。v1.61.0 フランス語サインオフで唯一の LOW 項目。(MINOR-001)


[1.61.0] — 2026-05-22

feat(i18n): フランス語を9番目のUI言語として追加。 新しいロケール別辞書 public/js/lib/locales/i18n-dict.fr.js(window.__I18N_DICT_FR)は英語と668キーの完全な同等性を持ち、新しいヘルプバンドル docs/help/fr.md(19 H2 / 73 H3en と正確な構造的同等性)。fr は言語スイッチャーとブラウザ自動検出(i18n.js)、アセンブラ(i18n-dict.js)、index.html(アセンブラより前の <script> タグ)、テストスナップショット、すべてのテストロケールリストに登録済み。初期翻訳テーブルは PR #9(コミュニティ貢献)由来。ロジック変更なし:t() とすべてのビューは不変。ユニットテスト 1001 / 1001;Playwright のロケールスイープは9サブテストに拡大。(FR-LOCALE)


[1.60.0] — 2026-05-22

refactor(i18n): 8 言語まとめのメガファイルをロケール別ファイルに分割 (I18N-SPLIT). 翻訳辞書は単一の public/js/lib/i18n-dict.js にありましたが、public/js/lib/locales/ 配下のロケールごとに 1 ファイルと共通の i18n-dict.aliases.js に分割し、翻訳者が 1 言語だけを独立して編集できるようにしました(i18next / OpenWA 方式)。i18n-dict.js は同じ window.__I18N_DICT を再構築するアセンブラになり、t() も各ビューも不変です。<script src> で同期読み込み — ビルドも fetch もなし。スナップショットで無損失移行を保証(678 キー)。ツールと約 25 のテストを分割対応に更新。新規 tests/i18n-locale-files.test.mjstests/playwright-locale-sweep.mjs(全ページ × 8 ロケールを実 Chromium で検証)。994 → 1000 ユニット · 62 → 70 Playwright。挙動の変更なし。(I18N-SPLIT)


[1.59.13] — 2026-05-21

fix(i18n): @alias で真の重複キーを統合 + 個人データの最終一掃. メンテナの実名をテストフィクスチャと QA レポートから除去(→ Jane Doe)、LICENSE/package.jsonFighter90 ハンドルへ。@alias 機構で全 8 ロケール一致の 10 キーを統合。nav.config/config.title はスペイン語で異なるため統合しない。991 → 994 テスト。(I18N-CL3)


[1.59.12] — 2026-05-21

fix(i18n): i18n-dict.js のクリーンアップ — fr 前 (I18N-CL1, I18N-CL2, I18N-CL4). training.coursePh の個人データを汎用プレースホルダに置換、followup.lastPh を固定日付から書式ヒントへ、npm run audit:i18n を追加。重複値グループは意図的(UI ロールが異なる)— 辞書ヘッダ参照。(I18N-CL1, I18N-CL2, I18N-CL4)


[1.59.11] — 2026-05-21

fix(test): v1.59.11 — e2e-comprehensive スイートが 23/23 パス(以前 11/23)。 Playwright の page.goto がハッシュのみ変更で no-op になる問題が根本原因。新しい goRoute(hash) ヘルパーが about:blank を経由して実ナビゲーションを強制。(e2e-harness-r1)


[1.59.10] — 2026-05-21

fix(api): NEW-F1-sub-r1 (v1.59.10) — 生 .. ガードをすべての /api ルート登録の上に移動。 v1.59.8 のものは app.all の後で発火しませんでした。Express 正規化前に実行されます。(NEW-F1-sub-r1)


[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 で承認されたドクトリン例外。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/cvCache-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.getapp.all。(NEW-F1)


[1.59.4] — 2026-05-20

fix(ui): NEW-OR1 (v1.59.4) — #/config Active/Keys チップのレース解消。 atomic replaceChildren + in-flight トークン + last-good キャッシュ。(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 すべてに初回起動クリーンアップセクションを追加。 初回スキャン前に 2 つの 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 行は対応する設定タブに直接ジャンプするゴーストボタンを表示します。(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 のディスパッチ・購読・全アドバイザビューでの呼び出しを静的に保証します。(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)を表示。#/configLLM_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) は router マウント前に発火していた。fix: headings の直接参照 + 二重 requestAnimationFrame。947 → 948 ユニット。(UX-A5)


[1.58.51] — 2026-05-20

chore(docs): v1.58.51 — v1.58.37 → v1.58.50 サイクル(14 releases)の最終ハウスキーピング。 コード変更なし。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 として close。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 対応。CI-isolated テスト 4 件。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 由来のスラグに置換。 以前はプレースホルダがそのまま表示されていた。新 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 が現在表示中の H2 に対応する TOC リンクに .toc-current を付与。938 → 939 ユニット。(UX-D-K)


[1.58.44] — 2026-05-20

fix(ux): UX-D-L — #/deep で開いた Saved-research の brief にインライン × クローズボタンを追加。 以前はスクロール・ナビゲーション以外で閉じる手段がなかった。新キー deep.closeBrief × 8。937 → 938 ユニット。(UX-D-L)


[1.58.43] — 2026-05-20

fix(ux): UX-D-F — #/evaluate で空送信時に専用のローカライズトーストを表示。 以前は「短すぎる」と同じメッセージ。新キー 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 を追加(新 advisor.eta キー × 8)。935 → 936 ユニット。(UX-D-J)


[1.58.41] — 2026-05-20

fix(ux/truthfulness): UX-D-I — コストヒントがタブ復帰時 + providers-changed イベントで再取得。 以前は 1 回のみ取得していたため、別タブでプロバイダを変更すると古い値が表示されていた。934 → 935 ユニット。(UX-D-I)


[1.58.40] — 2026-05-20

fix(ux/docs): UX-D-H — career-ops.org/docs/... 深層リンクがクリック可能であることを保証する regression-lock。 新しい 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 ボタンが明示的なフィードバックを提供。 ページリロードなしで再フェッチ + 再レンダリング。2 つの新 i18n キー。931 → 932 ユニット。(NEW-D2)


[1.58.38] — 2026-05-20

fix(a11y): NEW-D3 (WCAG 4.1.2) — #/tracker 検索入力にプレースホルダとは異なるローカライズ aria-label を追加。 以前は placeholder のみで SR には目的が伝わらなかった。新 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.mjscontacto.title / health.title の RU の漏れも検出して同時修正。928 → 930 ユニット。(NEW-D1)


[1.58.36] — 2026-05-20

chore(docs): v1.58.36 — v1.58.x サイクル終了時の完全ハウスキーピング sweep。 コード変更なし。(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 drawer、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 のバグ: .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 のキャプチャ上に: 新 API 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 — トーストジャーナル (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 列ヘッダにローカライズされた情報チップ ⓘ + ツールチップで High/Caution/Suspicious スケールを説明。 新規 i18n キー track.col.legitimacy.help × 8 言語。923 → 924 ユニット。(U-11)


[1.58.30] — 2026-05-20

fix(ux): U-10 — Tracker の Normalize / Dedup / Merge ボタンが data/applications.md 空のとき無効化。 ローカライズされたツールチップ (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 つのモードページで生成プロンプトブロックがデフォルト折り畳み。 <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” チップにツールチップ + aria-label で N と M の意味を提示。 新規 i18n キー scan.activeCo.help × 8 言語。918 → 919 ユニット。(U-6)


[1.58.25] — 2026-05-20

fix(ux/ia): U-5 — Dashboard の CTA を整理(ヘッダの Open Pipeline ボタンと Quick-action の Scan all sources タイルを削除)。 サイドバーとヒーロが既に両ルートをカバーしており、v1.58.3 QA の 4× Pipeline / 4× Scan を 2× ずつに減らした。917 → 918 ユニット。(U-5)


[1.58.24] — 2026-05-20

fix(ux): U-4 — エラートーストの “(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 — #/followuplastContact プレースホルダを今日 − 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 が先頭の のせいで 2 行に折り返さないようにした。 auto.title から を分離し、<span class="page-icon" aria-hidden="true"> に移動。.page-header--icon は grid レイアウトで絵文字専用列を確保。914 → 915 ユニット。(U-2)


[1.58.21] — 2026-05-20

fix(ux): U-1 — #/cv の H1 + サブタイトルが他ページと統一(v1.56.0 UX-9 のチップを設計上撤回)。 .cv-breadcrumb チップを削除し、<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、ヒント)に cadencefollow-upscopetimeline が混じっていたが、ロシア語ネイティブ表現に置換。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 が混在していた(ru/ja/ko/zh-CN/zh-TW)。今は 8 言語全てで完全にローカライズ。913 → 914 ユニット。(I-3)


[1.58.17] — 2026-05-20

fix(i18n): I-2 — Saved-research の日付ラベルを Intl.RelativeTimeFormat でロケール化。 public/js/views/deep.jsformatRelative() は英語の today / 1d ago / Nd ago をハードコードしていた。Intl.RelativeTimeFormat(I18n.getLang(), { numeric: 'auto' }) に置換 — ブラウザネイティブで「今日/昨日」「сегодня/вчера」等のローカライズ表現を取得。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 はあらゆるブラウザでスムーズに補間される。.btntransition 一覧に filter var(--transition) を追加して減光がアニメーションする。911 → 912 ユニット。(ユーザー報告)


[1.58.15] — 2026-05-20

fix(a11y/i18n): I-1 — トップバー検索の aria-label と非表示 <label> を i18n 化。 従来は全 8 言語で英文の aria-label がスクリーンリーダーに読まれていた。public/js/app.js に汎用 data-i18n-aria-label フックを追加 — applyI18n()data-i18n / data-i18n-placeholder と同様に言語変更時に aria-label を差し替える。新規 i18n キー 2 つ(top.search.ariatop.search.label)を 8 言語に追加。任意の将来のコントロールでも再利用可。910 → 911 ユニット。(I-1)


[1.58.14] — 2026-05-20

fix(ux): M-9 — 接続バナーの「更新」ボタンにフィードバックを追加(従来は無音リロード)。 v1.58.13 以前はクリックで即 location.reload() を呼んでいた。今は「更新中…」トーストを即表示し、sessionStorage['refreshedToast'] をセット、ボタンを disabled に(連打で重ねない)、リロードを 200ms 遅延させてトーストを描画。次回ブートで app.js がフラグを検出し、成功トースト「更新しました」を出す。新規 i18n キー 2 つ(common.refreshingcommon.refreshed)を 8 言語で追加。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)。状態は localStorage['applyChecklist:'+slug] に URL ごとに永続化 — 3 つチェック → リロード → 3 つとも残る。ボタン:未チェック項目をコピー(未消化の項目を - markdown で書き出し)と リセット。新規 i18n キー 5 つ(apply.checklist.copyUnchecked, resetBtn, copied, copyFailed, reset)を 8 言語で追加。パーサが項目を見つけなかった場合の防御的フォールバックあり。908 → 909 ユニット。(M-8)


[1.58.12] — 2026-05-20

fix(ux): M-7 — コストヒントがアクティブプロバイダに追従(OpenRouter で誤った固定額が出ない)。 UI.providerCostHint() は既に /api/status/providers 経由でプロバイダ対応していたが、public/js/api.js のマップに anthropic/gemini/openai/qwen のみ。v1.57.0 で OpenRouter が 5 番目のプロバイダとして加わってからも汎用フォールバック 0.03 に落ち、表示名も小文字 openrouter のままだった。今回 EST に openrouter: null を追加(ルーターがモデルを選ぶためコストは可変)、=== null 分岐でローカライズされた「cost varies (router picks)」を出力。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(タイトルと日付の間に空白なし)が確認された。原因は 2 つの裸の <span> の間の style="margin-left: 8px" インラインに依存しており、特定エントリで崩れていたこと。public/js/views/deep.js を修正 — 2 つの <span>.saved-card__title + セマンティックな <time class="saved-card__date" datetime="…"> に置き換え、フレックスコンテナ .saved-card でラップ。間隔は gap: var(--space-2, 8px) で制御するため崩れず、<time> で a11y/SEO の意味付けも得られる。906 → 907 ユニット。(M-4)


[1.58.10] — 2026-05-20

fix(ux): M-2 — 結果モーダル表示前に進捗トーストを排水。 #/cvsync-check クリック時、「Running cv-sync-check.mjs…」トーストが右下に残ったまま結果モーダルが開き、注目を奪い合い狭い画面では視覚的に重なっていた。Health ページの Doctor / verify-pipeline ボタンは UI.modal() 前に UI.dismissToast() を明示呼び出ししていたが、cv.js の sync-check のみ抜けていた。public/js/api.jsUI.modal() の最初の実行文として dismissToast() を呼ぶよう変更(境界での多層防御)。あわせて cv.js のハードコード英語文字列を t('cv.syncCheckRunning') / t('cv.syncCheck') に置換し、BUG-008 不変条件(モーダルタイトル == ローカライズボタンラベル)も満たす。新規 i18n キー 2 つを 8 言語で追加。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): OPENAI_API_KEY / QWEN_API_KEY / OPENROUTER_API_KEY#/health に表示(GEMINI_API_KEY と同様)。 v1.57.0 で OpenRouter が 5 番目のヘッドレス live-eval プロバイダとして追加され、v1.55.3(UX-2)で 4 プロバイダのオンボーディングも表示されるようになった。しかし #/health ページでは GEMINI_API_KEYANTHROPIC_API_KEY のみ表示され、残り 3 つはルーティング対象でありながら見えない状態だった。ユーザー要望:「set / unset (manual mode)」行のパターンを全ヘッドレスプロバイダに拡張。server/lib/routes/health.mjs に 3 つの任意チェック行を追加(/api/status/providers と同じ isUsableKey ゲートに接続)。hasOpenAIKey() / hasQwenKey() / hasOpenRouterKey() は既にインポート済みで未使用だった。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 の Option A(正規表現をメッセージに合わせる)で、[server/lib/security.mjs](https://github.com/Fighter90/career-ops-ui/blob/main/server/lib/security.mjs) に新規TEMPLATE_PATTERNS 配列(/${[^}]}//{{[^}]}}/)を追加し、new URL(…)の前にhasTemplatePlaceholder(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-patch した window.fetch で計測)、#/followup の Run live を一度クリックしただけで /api/mode/followup への同一 POST が約 2 秒以内に 2 件 観測されました(company/role/notes 入力済み、日付は空欄)。fix-prompt の「まず再現せよ」原則に従い、public/js/views/mode-page.js::submit() を精査した結果:(a) Run live と Generate prompt はいずれも <button> 要素で onClick を 1 つだけ持ち、親 <form>addEventListener('submit') もないため二重発火が成立しない、(b) UI.withSpinner()(FIX-L1)がリクエスト発火中は button.disabled = true を設定し、二度目の物理クリックを根本でブロック、の 2 点が確認できました。tests/playwright-smoke.mjs に新規テストを追加し、リグレッションの再現レシピを忠実に踏みます — company/role/notes を入力し、日付を意図的に空欄のままにし、Run live と同じ submit() を呼ぶ手動ボタンを 1 回クリックして、3 秒間で POST /api/mode/followup正確に 1 件 であることを検証します。ロケール非依存のセレクタ(8 言語すべてで グリフは同一)を採用し、同一ブラウザコンテキスト内で先行する言語切替テストの影響を防ぐため addInitScriptcareer-ops-ui:lang=en を事前注入。Playwright 59 → 60。元の QA 観測はレシピとして記録するに留め、製品コード変更は不要。(NEW-3)


[1.58.4] — 2026-05-19

fix(security): NEW-1 — すべてのレスポンスに Content-Security-Policy を付与(従来はループバック時に欠落)。 v1.58.4 以前は isPubliclyExposed() が真(HOST がループバック外)のときだけ CSP ヘッダーを付与していたため、127.0.0.1 上では //api/health も CSP なし で応答し、UI.md() のエスケープ優先契約が唯一の 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 ルート)で CSP 違反 0 を検証。ユニット 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>)がそのまま保存ブリーフに出ていた。最終の保守的スイープで、単独の足場トークン(開閉・均衡不問)、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 の残りは one-fix ship でキュー(バッチ不可)。


[1.58.2] — 2026-05-19

fix(i18n): I18N-011 — #/help の目次を非 EN 7 ロケールでローカライズ。 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-001 #/followup の任意の日付をクライアントで ISO YYYY-MM-DD 検証; BUG-003 ブロック引用内でも **太字**/`code`/リンクが描画(全 Help ページ); BUG-005 重複 URL は「すでにキューにあります — スキップ」; BUG-006 無効 URL メッセージを人間向けに((POST /api/pipeline · HTTP 400) 文脈は意図的に維持); BUG-007/008 「Running doctor.mjs…」トーストをモーダル前に消す(新 UI.dismissToast())、モーダル題はボタンのローカライズ済みラベル; BUG-010 #/reports 空状態にサブタイトル; BUG-002/UX-032 checkProfileCustomized() がテストフィクスチャ名を「未カスタマイズ」と判定(親の profile.yml/cv.md は不変 — ルール #1); I18N-012/013 ロシア語 Deep research を実翻訳。新規: cleanLlmMarkdown() がエージェント足場(<tool_call>{…}</tool_call>, <tool_response>, <thinking> …)を #/deep・保存済み調査から除去(全プロバイダ+保存済みファイル配信時); #/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 をメッセージにサイト全体で畳み込み(1 箇所の修正で全フォームが恩恵)、リクエスト文脈 (メソッド /パス · HTTP NNN)(どこで)を付与、非 JSON レスポンスは生本文の断片を表示、ネットワークエラーにもメソッド+パスを付与。err.details も公開。validateConfig のメッセージは最大限に説明的(何が悪く、どう直すか)に。シークレットキーは入力値を一切エコーしません(文字数のみ)—実キーの打ち間違いがトースト/ログに漏れません。PORT の範囲も実際に検証(99999 は拒否)。/#/config の PORT/HOST は実デフォルト(4317 / 127.0.0.1)を初期表示。エラートーストは長め(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 キーを保存しても「validation failed」になる不具合を修正。 貼り付けたキーは末尾の改行や空白を伴うことが多く(OS のクリップボード、プロバイダコンソールの「コピー」ボタン)、1.57 以前は すべての プロバイダで改行ガードに引っかかり、さらに $ 終端アンカーの ANTHROPIC_API_KEY 正規表現が本物の Anthropic キーを誤って弾いていました。validateConfig は検証の に各値を正規化(トリム)し、ルートはトリム後の値を保存(ランタイムで認証成功、\n による .env 破損なし)、Anthropic チェックは堅牢な sk-ant- プレフィックス + 長さに変更(共通の isUsableKey() ≥ 20 文字が本当の「実在キーか」判定)。内部改行は引き続き拒否(.env インジェクション対策)。OpenRouter が一級プロバイダに:/#/configOPENROUTER_API_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 互換クライアント(新規依存なし — 直接 fetchAbortController タイムアウト、キーは記録しない)で推奨の HTTP-Referer/X-Title ヘッダ付き。モデルのドロップダウンはライブ:OPENROUTER_MODELGET /api/openrouter/models(OpenRouter 公開カタログのサーバ側プロキシ — CSP connect-src 'self' を維持)から取得し、取得失敗時は厳選フォールバック、10 分間のメモリキャッシュ。8 ロケールに新 i18n キー(config.openrouter*)。テスト: 新規 tests/openrouter-route.test.mjstests/openrouter-model-selector.test.mjsenv-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 Karia-hidden="true"(既存の aria-label が AT に伝えるため二重通知を避ける)かつ pointer-events:none(装飾)。既存の Cmd/Ctrl+K キーバインドは不変。新しい i18n キーなし(グリフは共通);バッジは既存 .searchbar の flex 子(ラッパー/絶対配置不要 — input は既に flex:1)。テスト: 新しい CI 隔離のソース静的スイート tests/cmdk-hint-visible.test.mjs(5):.searchbar 内に <kbd class="kbd-shortcut">;aria-hidden="true" + data-mac/data-other 両方;app.jsnavigator 判定で埋める;(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


[1.56.3] — 2026-05-19

fix(reliability): プロバイダーのキー検出が空文字だけでなくプレースホルダー / 短すぎる値も拒否。.env のプレースホルダー GEMINI_API_KEY が「✓ set」と表示され、かつ有効な ANTHROPIC_API_KEY を差し置いてアクティブプロバイダーに選ばれていた。effectiveEnv()undefined/'' しか弾かないため、10 文字のゴミが本物のキー扱いに:オンボーディングバナーが GEMINI ✓ setGET /api/status/providersactiveProvider: "gemini" を返し、有効な 108 文字の Anthropic キーを無視して死んだキーで全ライブ ⚡ 評価が無言で失敗していた。新しい純粋関数 isUsableKey()(env-config.mjs)はシークレットを「設定済み」とみなす条件を ≥ 20 文字(どの対応プロバイダーのキーもこれより短くない — Gemini AIza… ≈ 39、Anthropic sk-ant-… ≈ 100+、OpenAI ≥ 40、Qwen ≈ 35)かつ既知のプレースホルダー(your_*_herechangemeplaceholder<…>、同一文字の繰り返し…)でないこと、に限定。hasAnthropicKey()/hasGeminiKey()(anthropic.mjs)、hasOpenAIKey()/hasQwenKey()(openai.mjs)、GET /api/healthGEMINI_API_KEY/ANTHROPIC_API_KEY 行(生 process.env から同じ effective+plausible ビューへ移行)に一律適用 — health ページ・プロバイダーエンドポイント・OR ルーターが常に一致。selectActiveProvider() は不変(正しい keysConfigured を受け取るだけ)。テスト: 新しい CI 隔離スイート tests/key-detection-rejects-placeholder.test.mjs(5):isUsableKey 単体 + in-process createApp() で報告シナリオを再現(一時 .env に 10 文字 GEMINI_API_KEY + 実 ANTHROPIC_API_KEY)— geminikeysConfigured になく、activeProvider === "anthropic"/api/health 行も一致。既存の effective-env 階層テスト 4 件は短すぎるスタブを現実的な長さに延長(契約は不変)。821 → 826。fix(reliability) · test: tests/key-detection-rejects-placeholder.test.mjs。詳細は CHANGELOG.md


[1.56.2] — 2026-05-19

feat(a11y): UX-N1 — ルートごとのロケール対応 document.title(マルチタブの識別 + スクリーンリーダーのページ変更通知)。 修正前は 24 ルートすべてが index.html の静的 <title>(「career-ops — command center」)のままで、タブ名が同一・ブックマークが汎用・「ページが変わりました」通知も毎回同じだった。public/js/router.jsfocusNewView() がビュー自身のローカライズ済み <h1 class="page-title"> からタイトルを導出 — 「ビュー — career-ops」— するため、自動翻訳(新しい i18n キー不要)かつルートごとに一意。初回ペイントの guard よりに設定するので最初のタブにもタイトルが付く(v1.56.0 UX-12 の tabindex 設定と同じ順序)。見出しが無いビューは career-ops — command center にフォールバック。テスト: 新しい CI 隔離のソース静的スイート tests/document-title-per-route.test.mjs(4):focusNewViewdocument.title を代入;タイトルは <h1> 由来(ルートごと + ローカライズ、単一リテラルでない);代入は !firstPaintDone より前;製品デフォルトあり。817 → 821。feat(a11y) · test: tests/document-title-per-route.test.mjs。詳細は CHANGELOG.md


[1.56.1] — 2026-05-19

fix(a11y): ルーター管理の tabindex="-1" 見出しフォーカスで出ていた偽のブランドフォーカスリングを抑制。 public/js/router.js は各クライアント遷移で遷移先ビューの見出しに tabindex="-1" を付与し .focus() する(スクリーンリーダーが新ページを読み上げるため)。tabindex="-1" 要素はキーボードで到達不能だが、Chromium の :focus-visible ヒューリスティックが依然グローバルのブランドリング(*:focus-visible { outline: 2px solid var(--rausch) })を描き、遷移ごとに ページ見出しの周りに赤い矩形(例:#/dashboard の「Command Center」)を表示 — それが images/dashboard-*.png のヒーロー画像にも焼き込まれていた。修正は 1 つのスコープ付きルール [tabindex="-1"]:focus, [tabindex="-1"]:focus-visible { outline: none }(WAI-ARIA APG の管理フォーカス・パターン)。実際のキーボードフォーカスはグローバル *:focus-visible リングを維持(WCAG 2.4.7 維持);skip-link のリングは無影響(<a> であり tabindex="-1" ではなく、より高い詳細度)。8 つの images/dashboard-*.png を再生成 — 赤い枠は消えた。テスト: 新しい CI 隔離のソース静的スイート tests/managed-focus-no-ring.test.mjs(4):グローバル *:focus-visible リングが定義されたまま(WCAG 2.4.7 非後退);[tabindex="-1"]:focus,:focus-visibleoutline:none;抑制ルールはグローバルの後(カスケード安全);修正はスコープ付き(全体 *:focus{outline:none} なし)。tests/dashboard-initial-focus.test.mjs と対。813 → 817。fix(a11y) · test: tests/managed-focus-no-ring.test.mjs。詳細は CHANGELOG.md


[1.56.0] — 2026-05-19

feat(ux): LOW 仕上げバンドル — UX-9 / UX-10 / UX-11 / UX-12(1 つのグループ化マイナーリリース)。 UX-9 #/cv:ページタイトルを控えめな .cv-breadcrumb チップに降格し、うるさいサブタイトルは <h1>title ツールチップへ移動 — ユーザーの CV(プレビューの名前)が視覚的優先権を持つ。F-V54-A 不変は維持 — 依然 正確に 1 つの <h1>、依然 .page-titleUX-10 新しい共有ヘルパー UI.providerCostHint(t)#/auto#/evaluate#/deep・各 #/<mode> の ⚡ ライブ実行の隣に表示;GET /api/status/providers(v1.55.3)を再利用:キーありで 「推定コスト: OpenAI gpt-5-codex · ~$0.04/eval」(桁レベル、“~”)、キーなしで ⚡ は手動プロンプトをコピー(API コストなし)と明示;fail-soft。UX-11 #/help:TOC フィルタが ちょうど 1 つ のセクションに絞られたら 300ms アイドル後にそこへスクロール(デバウンス;0 や 2 以上では発火しない)。UX-12 #/dashboard:初回ペイントで <h1> をフォーカス可能(tabindex="-1")にし、#contentaria-live="polite" を維持(起動時に読み上げ)— フォーカスは 奪わない(skip-link との競合回避、v1.41.0 の決定)。新 i18n キー cost.estimatecost.manual ×8;新しい .cv-breadcrumb/.cost-hint CSS。テスト: 4 つの新しいソース静的 CI 隔離スイート(cv-breadcrumb 3、run-cost-line 4、help-toc-autoscroll 4、dashboard-initial-focus 3);既存 cv-single-h1/help-nav-a11y ロック更新(不変保持)。800 → 813。4 つのライブ Playwright プローブ、コンソールエラー 0。feat(ux) · 4 test suites。詳細は CHANGELOG.md


[1.55.8] — 2026-05-19

feat(tracker): サーバーサイド・ページネーション + クリック可能なファネルチップ(UX-8)。 サーバー: GET /api/tracker任意?page / ?pageSize / ?status クエリパラメータを追加。無しなら応答は従来の { rows: [...] } とバイト単位で同一(既存の呼び出し元/テストは無影響)。有りなら { rows: slice, total, page, pageSize, funnel } を返す — pageSize[1,500]page≥1 にクランプ、statusrows+total をフィルタ、funnel全履歴のステータス→件数内訳(ページ/フィルタに依存しないのでチップが常に正確)。#/tracker: 上部に新しいクリック可能なファネルチップバー「すべてのステータス · N · Applied · N · Interview · N …」(順序 Applied → Responded → Interview → Offer → Rejected → Discarded → Evaluated → SKIP)。チップのクリックで Status フィルタを設定(アクティブなチップの再クリックで解除);アクティブチップは aria-pressed + ハイライト。8 ロケールの新 i18n キー track.funnelAria;新しい .tracker-funnel/.tracker-chip/.tracker-chip--active CSS。test: tests/tracker-server-paged.test.mjs(新規、7 ケース、CI 隔離、エフェメラルポートのインプロセス Express + 一時 CAREER_OPS_ROOT applications.md — CLAUDE.md #2/#8):back-compat(パラメータ無しで厳密に {rows});?page&pageSize スライス + total/page/pageSize/funnel 合計 N;最後の部分ページで重複なし;範囲外ページ ⇒ 空 rows + 有効 total;?status= が total/rows をフィルタしつつ funnel は全履歴;pageSize キャップ;+ チップバーのソース静的ロック。793 → 800。feat(tracker) · test: tests/tracker-server-paged.test.mjs。詳細は CHANGELOG.md


[1.55.7] — 2026-05-19

feat(pipeline): >1000 行で vanilla-JS の行仮想化(UX-7)。 #/pipeline行を描画(filtered.forEach(list.appendChild(urlRow)))していた — スキャンはキューを数千の URL で満たすため、数千の行ノード(各々 flex div + <a> + ボタン 2 個)がフィルターのキー入力ごとに同期構築され、DOM とアクセシビリティツリーを溢れさせた。新しい vanilla-JS 仮想化(react-window 相当、依存なし):VIRTUALIZE_THRESHOLD = 1000 超で #/pipeline は固定高(70vh)のスクロールビューポートになり、縮まないスペーサー(flex:0 0 autoheight = 行数 × 56px)がリスト全体の実スクロールバーを保ち、rAF スロットルのスクロールリスナーがビューポート ± 5 行バッファのみ描画(一度に N ではなく ~16–19 ノード)。閾値以下では元の単純描画をバイト単位で維持するため、典型的なパイプラインと既存テスト/e2e は影響なし。各仮想化行は URL で曖昧性を解消した ▶/✕ aria-label を維持(F-V54-B 回帰ロック)。ウィンドウ計算は純粋な computeWindow() ヘルパー。test: tests/pipeline-virtualize.test.mjs(新規、5 ケース、CI 隔離、ソース静的):~1000 の数値閾値;≤閾値分岐は forEachappendChild 維持;>閾値分岐は rAF スクロールリスナー + スペーサーで slice(start,end) 描画;computeWindow()[0,total] ± バッファでクランプ;行が ▶/✕ aria-label 維持。788 → 793。ライブ Playwright プローブ(1200-URL フィクスチャ):scrollHeight≈67248、DOM に ~16–19 ノードのみ、ウィンドウがスクロールを端から端まで追従、コンソールエラー 0。feat(pipeline) · test: tests/pipeline-virtualize.test.mjs。詳細は CHANGELOG.md


[1.55.6] — 2026-05-19

feat(scan): 副次フィルターを「詳細フィルター」ディスクロージャの背後へ整理(UX-4)。 #/scan は全フィルター — フリーテキスト、リモート/ハイブリッド/オンサイト、スコープ、ソース、スキャン後の stack/level/dynamic ファセットチップ — を同じ重みで積み上げ、コントロールの壁だった。今や日常フィルターは可視のまま(フリーテキスト + リモート/ハイブリッド/オンサイト;🌐 スキャンボタンは既にコントロールカードに別置)、副次は <details class="scan-advanced"><summary>詳細フィルター</summary> の背後に折り畳み:スコープ + ソースのセレクト、そして別途ファセットチップ群(新しい結果集合がチップの壁ではなくテーブルで始まり、チップ行が 1 つ以上ある時のみ描画)。8 ロケールの新 i18n キー scan.advancedFilters;新しい .scan-advanced サマリースタイル(控えめな ⚙ アフォーダンス、マーカーなし、開時に太字)。test: tests/scan-advanced-disclosure.test.mjs(新規、6 ケース、CI 隔離、ソース静的):.scan-advanced フック + scan.advancedFilters ラベルの <details>/<summary> が存在;フリーテキスト + リモートは可視のまま;スコープ + ソースはディスクロージャ内;chipsContainer<details>;.scan-advanced summary がスタイル付き;scan.advancedFilters ×8。782 → 788。feat(scan) · test: tests/scan-advanced-disclosure.test.mjs。詳細は CHANGELOG.md


[1.55.5] — 2026-05-19

feat(dashboard): 2 つの P0 CTA + 焦点となる最近のアクティビティヒントのヒーロー(UX-3)。 #/dashboard は同じ重みの約 30 ノードで開き、「次に何をすべきか」が不明瞭だった。新しい .dash-hero ブロックがページヘッダー直下に配置:2 つの P0 ジャーニー — ✨ URL を自動パイプライン🌐 今すぐスキャン — を大きな .btn-hero ボタンに昇格し、単一の 焦点となる最近のアクティビティヒント(「最新の評価: <スコア><タイトル>」、レポートへリンク;コールドスタートでは dash.heroNoEval の案内空状態)が、再訪ユーザーには中断地点を、新規ユーザーには重要な唯一のアクションを示す。2 つの主要ボタンはヘッダーから削除(副次的な「📋 パイプラインを開く」のみ残置)しアクションの重複を回避。ステータスバケットは目立つ .badge から控えめな .dash-chip ピルへ降格。8 ロケールの新 i18n キー dash.lastEvaldash.heroNoEval;新しい .dash-hero/.btn-hero/.dash-chip CSS。test: tests/dashboard-hero.test.mjs(新規、5 ケース、CI 隔離、ソース静的):.dash-hero が存在し Quick-actions グリッドに先行;両 P0 CTA が /auto+/scan ルートの .btn-hero;焦点 dash.lastEval + 空状態 dash.heroNoEval;バケットが .dash-chip;CSS 存在;dash.lastEval+dash.heroNoEval ×8。777 → 782。feat(dashboard) · test: tests/dashboard-hero.test.mjs。詳細は CHANGELOG.md


[1.55.4] — 2026-05-19

feat(ux): Run の隣に正直な auto-pipeline ETA + スキャン中の目立つ Stop(UX-6)。 #/auto:新しい .auto-eta ヒント — “⏱ 約1〜2分”(キー auto.etatitleauto.etaTitle)— が Run ボタンの隣に表示され、ワンクリックの約束が所要時間について コミット前に 正直になる;文言は career-ops.org/docs(「URL を貼る → 1〜2 分で完全レポート」)と一致。#/scan:数分のクロールが実行中(aria-busy)の間、Stop を低コントラストのゴーストボタンから目立つ破壊的ボタンへ昇格(新しい .btn-danger — 塗りつぶし、高コントラストの白文字 on コーラル、太さ 600)。setScanRunning(running)scan-stop-btnbtn-danger(実行中)と btn-ghost(アイドル、どのみち非表示)で切り替え、負荷時でもユーザーが Stop を見つけ信頼できるようにする。8 ロケールの新 i18n キー auto.etaauto.etaTitle;新しい .btn-danger/.auto-eta CSS。test: tests/auto-eta-stop.test.mjs(新規、4 ケース、CI 隔離、ソース静的):#/autorunBtn の隣に .auto-eta クラスで t('auto.eta') を描画;auto.eta ×8;setScanRunning(running) が Stop を btn-danger に昇格;.btn-danger が高コントラストの白文字で存在。773 → 777。feat(ux) · test: tests/auto-eta-stop.test.mjs。詳細は CHANGELOG.md


[1.55.3] — 2026-05-19

feat(onboarding): 画面上の 4 プロバイダ OR ステータス — コールドスタート・バナー + アクティブ・プロバイダ・チップ(UX-2、HIGH)。 新しい読み取り専用エンドポイント GET /api/status/providers{ activeProvider, activeModel, keysConfigured }keysConfiguredllm.mjs のゲートと同じ実効 env ビュー(process.env ∨ 親 .env);activeProvider は OR ルーターが実際に選ぶもの — env-config.mjs の新しい純粋ヘルパー selectActiveProvider()providerOrder() を走査(キーのない LLM_PROVIDER ピンは null)。秘密は返さない — プロバイダ名 + モデル id のみ。SPA シェルがグローバルなオンボーディング領域(#onboarding-bannerapp.js が描画、CSP 安全な DOM のみ)を表示:0 キー → 赤いバナー + #/config?tab=api-keys への CTA;≥1 キー → 控えめなチップ にアクティブなプロバイダ+モデル。看板の差別化要因(「Anthropic / Gemini / OpenAI / Qwen のいずれかが自動順で動く」)を試行錯誤ではなく画面上で発見可能にする。8 ロケールの onboarding.* i18n キー;新しい .onboarding-warn/.onboarding-ok CSS。test: tests/onboarding-key-banner.test.mjs(新規、9 ケース、CI 隔離):selectActiveProvider の意味論;GET /api/status/providers のインプロセス(エフェメラルポート + 一時 CAREER_OPS_ROOT .env で実際の親キーを決して読まない — CLAUDE.md #2/#8);静的 SPA 配線 + onboarding.* ×8 カバレッジ。764 → 773。feat(onboarding) · test: tests/onboarding-key-banner.test.mjs。詳細は CHANGELOG.md


[1.55.2] — 2026-05-18

fix(cv): #/cv マークダウンエディタに記述的で自己完結したアクセシブル名を付与(F-V55-H / UX-5)。 #/cv の主エディタ <textarea id="cv-editor"> は今や新キー cv.editorAria 経由で記述的な aria-label“CV マークダウンエディタ — マークダウン形式のプロフェッショナル履歴書” — を持ち、可視の「Markdown」セクション見出しから継いでいた簡素な名前を置き換える。注:F-V55-H の症状(aria-label/labels のみ検査)と異なり、このフィールドは名前が無かったわけではない — v1.47.0(WS2 #16)が既に aria-labelledby<h3 id="cv-md-heading">Markdown</h3> で結び付けており、スクリーンリーダーは「Markdown、編集、複数行」と読み上げていた。v1.55.2 はその簡素な「Markdown」を自己完結ラベルへ改善する。冗長な aria-labelledby は削除(残れば死んだマークアップ — ARIA 優先順位で aria-label が勝つ);可視の <h3>Markdown</h3> は晴眼ユーザー向けに残る。WCAG 1.3.1 + 4.1.2;v1.54.5 の batch-tsv 修正(F-V54-C)と並行。test: tests/cv-editor-a11y.test.mjs(新規、3 ケース、CI 隔離、auto-stepper-prerender.test.mjs 流のソース静的):#cv-editor は空でないフォールバックと共に t('cv.editorAria', …) で自己命名;cv.editorAria は 8 ロケール全てに存在し空でない;要素に冗長な aria-labelledby なし。761 → 764。fix(cv) · test: tests/cv-editor-a11y.test.mjs。詳細は CHANGELOG.md


[1.55.1] — 2026-05-18

fix(auto): #/auto マウント時に 5 段階パイプラインのステッパーを事前レンダリング(F-V55-E / UX-1、シニア観察 S-4 再オープン)。 #/auto は今や、文書化された 5 段階の概要 — 検証 → 取得 → 評価 → レポート保存 → トラッカー追加 — を画面マウントの瞬間に表示する。以前は最初の SSE イベントまで空白だった。従来は <ol class="auto-stepper">display:none で生成され、renderStepper()setStep() / run() からのみ到達したため、コールドスタートのユーザーは Run をクリックする前にドキュメントが約束するパイプラインを決して見られなかった。ステッパーは今やマウント時に 5 段階すべてが pending 状態で可視となり、aria-label(auto.stepperAria)を持つため支援技術がその領域を読み上げる。F-V55-E(a11y/静的保証レンズ)と UX-1(約束忠実度レンズ)をクローズ — 同一修正、両レンズ。test: tests/auto-stepper-prerender.test.mjs(新規、4 ケース、CI 隔離、router.test.mjs 流のソース静的):STEPS 配列は正確に 5 つの正準段階が順序どおり;stepperEl はマウント時に display:none ではなく auto.stepperAria を持つ;マウントスコープの renderStepper() 呼び出しが function setStep( に先行する;auto.stepperAria は 8 ロケール全てに存在。757 → 761。fix(auto) · test: tests/auto-stepper-prerender.test.mjs。詳細は CHANGELOG.md


[1.55.0] — 2026-05-18

feat(llm): ヘッドレス・ライブ評価が “OR” で動作 — Anthropic | Gemini | OpenAI | Qwen、どのキーが設定されているかで自動選択。 ユーザー要望により、web-ui の ⚡ ライブ評価は Anthropic/Gemini だけでなく設定されているどの API キーでも動作するようになった。LLM_PROVIDERopenaiqwen を追加;auto(既定)はキーが存在する最初のプロバイダを使い、Anthropic → Gemini → OpenAI → Qwen の順で優先する。明示値は 1 つを固定する;キーなしで強制されたプロバイダは依然として手動プロンプト経路へフォールバックする。新しい server/lib/openai.mjs — 依存ゼロの OpenAI 互換 Chat Completions クライアント(anthropic.mjs と同じ安全な直接 HTTPS パターン:AbortController タイムアウト、キーは決してログ出力しない、effectiveEnv() キー解決により親 .env のキーが再起動なしで動作)。1 つのコア(runOpenAICompatible)が runOpenAI(api.openai.com)と runQwen(Alibaba DashScope の OpenAI 互換モード;中国本土ホストは raw .envQWEN_BASE_URL によりエンドポイントを上書き)を支える。SDK なし、任意の CLI 実行なし — 親プロジェクトは CLI 非依存のまま(Claude Code · Codex · Gemini · OpenCode · Qwen · Copilot · Kimi);これはヘッドレスな API キー経路のみを拡張する。OpenAI/Qwen のテールは全評価サーフェスに配線済み:/api/evaluate/api/deep/api/mode/:slug/api/auto-pipeline SSE — auto の優先を保持するため Anthropic(インライン)+ Gemini(サブプロセス)分岐の後で参照され、Anthropic が使うのと同じバンドル済みコンテキストのインライン化を行う。env-config.mjs:QWEN_API_KEY(秘匿)+ QWEN_MODEL(非秘匿)を KNOWN_KEYS/KEY_GROUPS.core に追加;LLM_PROVIDERSproviderOrder() を拡張;OPENAI_API_KEY は今や第一級のヘッドレス・プロバイダ・キー(以前は保存のみ)。#/config API キータブ:LLM_PROVIDER セレクトに openai/qwen を追加;新しい QWEN_API_KEY + QWEN_MODEL フィールド(キュレートされた qwen-max/qwen-plus/qwen-turbo/qwen2.5-* リスト);タブ先頭の新しいノートが CLI 非依存の親 vs web-ui のヘッドレス評価と OR 順を説明する。8 ロケール全体に新しい i18n キー。test: tests/openai.test.mjs(新規、9 ケース、CI 隔離):OpenAI/Qwen 成功 + ブロック配列コンテンツ、Bearer 認証、既定および QWEN_BASE_URL 上書きエンドポイント、4xx/5xx/不正形式、max_tokens クランプ、タイムアウト、effectiveEnv キー検出、キー無漏洩カナリア。tests/provider-selector.test.mjs は v1.55.0 の providerOrder/LLM_PROVIDERS/SECRET サーフェス + OpenAI/Qwen テール配線向けに更新。748 → 757。feat(llm) · test: tests/openai.test.mjs · test: tests/provider-selector.test.mjs。詳細は CHANGELOG.md


[1.54.10] — 2026-05-18

fix(auto-pipeline): SSE クライアント切断の衛生 — 不安定な Playwright e2e ジョブを潰す。 Playwright e2e ジョブが断続的に赤になっていた(個別テスト 32/32 通過するが not ok 2 - tests/playwright-smoke.mjs):#/auto SSE ストリームが進行中にページを閉じると、サーバーの次の res.write()EPIPE/"aborted" で拒否され、—レスポンスに 'error' リスナがないため— Node がそれを uncaughtException に昇格させ、node:test が “asynchronous activity after the test ended” として報告した。auto-pipeline.mjsopenSse() は今や no-op の res.on('error') を登録し、send()res.writableEnded || res.destroyed で保護する(try/catch で包む)— 消えたクライアントは例外ではなく想定内である。これは単なるテスト修正ではなく、正しい本番 SSE 衛生である。tests/playwright-smoke.mjs:Cmd+K テストは実際の外向き URL(https://example.com/jobs/123)を使っていたがモーダル出現を待つだけだったため、closePage() がテスト終了後にサーバーの進行中の safeGet() を中断していた。今やパイプラインが終端状態に達するまで待つ(閉じる前に fetch が正常に解決するように)。共有 closePage() ヘルパ(window.stop() してから閉じる)と after フックの server.closeAllConnections() は多層防御として残る。検証:連続 8/8 グリーン実行(6× node --test + 2× browser-smoke)、以前は ~2 回に 1 回赤。tests/auto-pipeline.test.mjs +1 静的ケースで openSse 切断衛生コントラクトを固定(res.on('error') リスナ + writableEnded||destroyed ガード + try で包んだ書き込み)。747 → 748。fix(auto-pipeline) · test: tests/auto-pipeline.test.mjs。詳細は CHANGELOG.md


[1.54.9] — 2026-05-18

fix(llm): リクエスト時に親 .env の LLM キーを尊重する — 古い/無効なプロバイダへの誤ルーティングを停止。 ANTHROPIC_API_KEY が構成済みプロバイダであっても、ライブ評価が “Gemini API error: API key not valid” で失敗することがあった。根本原因: hasAnthropicKey() / hasGeminiKey()(および runAnthropic のキー/モデル検索)が起動時の process.env スナップショットのみを読んでいた。サーバー起動後に Anthropic キーが親 .env に追加されても、実行中プロセスはそれを決して見ず → Anthropic 検出が false になり、評価は process.env実際にあった古いキー(しばしば古く無効な GEMINI_API_KEY)へフォールバックした。Gemini 実行パス(親 Node サブプロセス)は既に親のライブ .env を読んでいたため、両プロバイダがキーを一貫しない形で解決していた。env-config.mjs の新しい effectiveEnv(key, envFilePath): 空でない process.env 値が優先(シェル export と POST /api/config のライブ適用をカバー)、そうでなければ現在の親 .env ファイルを参照する。anthropic.mjs は今や ANTHROPIC_API_KEYANTHROPIC_MODEL、Gemini キーチェックをこれ経由で解決するため、親 .env に設定されたキーがサーバー再起動なしで尊重され、キー検出がリクエストが実際に送るキーと常に一致する。プロバイダ順序は不変(auto → Anthropic-次に-Gemini);これは検出のみを修正する。キーは決してログ出力も返却もされない(REVIEW-B4 無漏洩テストは引き続き通過)。tests/anthropic.test.mjs は CI 隔離向けに書き直し(temp CAREER_OPS_ROOT、動的 import)、正確なバグを再現する 2 つの新ケースを含む(キーが親 .env のみ → 検出される;process.env が未設定のとき runAnthropic が親 .env のキー + モデルを送信)。tests/env-config.test.mjs +3 effectiveEnv ケース(process.env の優先、空文字列を未設定として扱う .env フォールバック、ファイル欠如 / キー欠如 / パスなし → undefined)— 新分岐の 100%。742 → 747。fix(llm) · test: tests/anthropic.test.mjs · test: tests/env-config.test.mjs。詳細は CHANGELOG.md


[1.54.8] — 2026-05-18

feat(config): Modes フィールドフォームが(空/スタブのファイルでも)常に career-ops.org のフィールドガイダンス付きで正規スキーマをレンダリングする。 v1.54.3 の Modes フィールドフォームは既存の ## セクションのフィールドのみをレンダリングしていた — そのため新規・空・スキーマ非準拠の modes/_profile.md(例:よくある 1 行スタブ)では “No ## sections found — use the raw editor below.” にフォールバックし、ユーザーはフィールドを得られなかった。ユーザー要望(“разбей по полям … описание полей возьми из career-ops.org/docs”)により、フォームは今や常に文書化された順序で 5 つの正規フィールドをレンダリングする(Target Roles, Adaptive Framing, Exit Narrative, Comp Targets, Location Policy)。ファイルにあれば事前入力され、なければ空だが編集可能 — そのため真新しいプロファイルもフォームだけで完全に記入できる。各フィールドは career-ops.org 正規 Quick Start §Step-5 由来の説明(Target Roles / Adaptive Framing / Exit Narrative / Comp Targets / Location Policy に何を入れるか)を表示し、スクリーンリーダー向けに aria-describedby で配線される。見出しバリアント許容:テンプレートの ## Your Target Roles(等)は ## Target Roles と同じ正規フィールドにマップされるため、テンプレートもサーバースキャフォールド慣習もフォームを壊さない。collect() は今やタグ付きペイロードである:レンダリングされた見出しがファイルの既存の見出しと正確に一致するときの非破壊的な { sections } マージ(前文 + 触れていない + カスタムセクションがバイト安定で残る)、またはファイルにスキーマが欠けていたときにスキーマ準拠ドキュメントをブートストラップ/正規化する { markdown } 全ファイル再構築。再構築パスは config.js確認ゲート付き(親ファイルを置き換える — WS2 #4 破壊的保存不変条件)、既存の前文(または文書化されたデフォルト)を保持し、非正規セクションを verbatim で維持する。8 ロケール全体に 6 つの新 i18n キー(config.modesDescTargetRolesconfig.modesDescLocationPolicy + config.modesFormRebuildBody)。tests/modes-form.test.mjs は v1.54.8 契約向けに書き直し:スキーマ + 正規順序、config.js のペイロード/確認配線、8 ロケールでの各フィールドの文書由来説明の存在、canonicalKey “Your X” 許容、リストのラウンドトリップ安定性、ブートストラップ常時レンダリング保証、そしてデータ安全性を備えたタグ付き sections-vs-markdown の collect()。実際の親スタブファイルに対してライブ検証済み(5 フィールド + 説明が表示、コンソールエラー 0)と隔離スタブフィクスチャ(記入 → 確認ゲート保存 → 5 つの正規セクションすべて永続化)。feat(config) · test: tests/modes-form.test.mjs。詳細は CHANGELOG.md


[1.54.7] — 2026-05-18

fix: W-001 — コード/スタイルのアセット + SPA シェルが Cache-Control: no-store で配信されていた(デプロイ衛生)。 SPA は api.js / router.js / 各ビューをバージョンクエリ文字列なしの素の <script src> でロードし、ビルドステップがない(コンテンツハッシュなし)ため、デプロイ後にブラウザがキャッシュされた古いバンドルを数時間配信し続けることがあった → クエリ文字列ルートで stale-cache 404(v1.29.2 回帰中にライブ観測;回帰ラン W-001)。server/index.mjs は今や express.staticsetHeaders フック経由で .js / .mjs / .css / .htmlCache-Control: no-store を設定し、SPA シェルの catch-all(sendFile を使い setHeaders を回避する)にも明示的に設定するため、ブラウザはルーティングを駆動するコードを常に再検証する。非コードの静的アセットは express.static のデフォルトキャッシングを維持する。セキュリティヘッダー(CSP / nosniff / frame-deny / referrer-policy)は不変 — 既存の security-headers スイート(8 ケース)が新テストと並んでグリーンで実行され検証済み。テストファイル tests/asset-cache-control.test.mjs を +1 — 4 ケース(JS アセット no-store、CSS no-store、静的 index.html no-store、SPA catch-all のディープルートシェル no-store)、隔離された CAREER_OPS_ROOT に対して実アプリをブート。さらに tests/playwright-smoke.mjs のフレーキーな teardown 修正(別の test(e2e) コミット):auto-pipeline の SSE スモークテストが今や finally でリーダーをキャンセル + fetch を中断し、after フックが残存ソケットを強制クローズして、v1.54.6 の Playwright e2e ジョブを赤くしていた teardown 後の “Error: aborted” を排除。738 → 742。fix · test: tests/asset-cache-control.test.mjs。詳細は CHANGELOG.md


[1.54.6] — 2026-05-18

fix(a11y): S-7 — #/help の back-to-top ボタンが正規のセレクタークラス back-to-top を持つ。 #/help のフローティング back-to-top ボタンは正しく動作していたが(ライブ検証済み)、そのクラスリスト(btn btn-primary help-back-top)は spec §2 #28 テストが狙う .back-to-top セレクター規約の外にあった — より厳格なセレクターならフレーキーだったはず(回帰ラン S-7、“イージーウィン”)。ボタンは今や正規の back-to-top クラスも持つ。純粋に加算的で CSS no-op:help-back-top(既存の CSS フック)は変わらず、back-to-top には CSS ルールがない — 安定したテスト/自動化ハンドルにすぎない。ライブ検証済み:document.querySelector('.back-to-top') がボタンを解決、aria-label 維持、コンソールエラー 0。tests/help-nav-a11y.test.mjs の既存 #12 ケースを、back-to-top ボタンのクラスリストが正規 back-to-top セレクターを含むというアサーションで拡張(新ファイルなし)。fix(a11y) · test: tests/help-nav-a11y.test.mjs。詳細は CHANGELOG.md


[1.54.5] — 2026-05-18

fix(a11y): F-V54-C — #/batch の TSV エディターにアクセシブルな名前がある。 #/batch の TSV <textarea>aria-describedby 経由で配線されたヒントはあったがアクセシブルな名前がなかった<label htmlFor> なし、aria-label/aria-labelledby なし(回帰ラン F-V54-C; WCAG 1.3.1 Info & Relationships / 4.1.2 Name, Role, Value)。aria-describedby名前ではなく説明を供給するため、スクリーンリーダーはラベルのない “edit text” を読み上げた。textarea は今や新しい i18n キー batch.tsvAria 経由の aria-label を持ち、すでに *Aria キーを使う兄弟のラン制御入力と一貫する;既存の describedby ヒントは保持される。ライブ検証済み:aria-label 存在 + ローカライズ、aria-describedby 維持、コンソールエラー 0。新しい i18n キー batch.tsvAria を 8 ロケール全体に追加。テストファイル tests/batch-tsv-accessible-name.test.mjs(2 ケース:batch-tsv ブロックが describedby ヒントを保ちつつ t(batch.tsvAria) 経由の aria-label を持つ;batch.tsvAria が 8 ロケールで定義)を +1;736 → 738。fix(a11y) · test: tests/batch-tsv-accessible-name.test.mjs。詳細は CHANGELOG.md


[1.54.4] — 2026-05-18

fix(a11y): F-V54-B — #/pipeline の行アクションボタンにアクセシブルな名前がある。 #/pipeline の行ごとの (評価)および (削除)ボタンは title 属性のみのアイコン専用だった(回帰ラン F-V54-B; WCAG 4.1.2 Name, Role, Value)。title は信頼できるアクセシブルな名前ではないため、スクリーンリーダーユーザーは区別のつかない “button” の長い連なりを聞き、削除がどの行に当たるか判別できなかった。両ボタンは今や、新しい shortUrl() ヘルパー経由のコンパクトな URL(host + …/ + 末尾 2 つのパスセグメント;パース不能な入力には末尾スライスのフォールバック)で曖昧さを解消した明示的な aria-label を持ち、a11y ツリーは例えば “Delete: hh.ru/…/vacancy/12345” と読み上げる。新しい i18n キーなし — common.delete / pipe.evaluateBtn + URL を再利用。ライブ検証済み:1385 行、各ボタン名が行ごとに一意、コンソールエラー 0。テストファイル tests/pipeline-row-action-names.test.mjs(4 ケース:両ボタンが shortUrl(url) で配線 + ちょうど 2 つのそのラベル、shortUrl が使用前に宣言、同一ホスト別求人の URL は collapse しない、ベアホスト / パース不能 / 空のフォールバック)を +1;732 → 736。fix(a11y) · test: tests/pipeline-row-action-names.test.mjs。詳細は CHANGELOG.md


[1.54.3] — 2026-05-18

feat(config): #/config の “Modes” タブ向け構造化フィールドフォーム(もう生の markdown ではない)。 “Modes” タブは modes/_profile.md## セクションごとに 1 つの生の <textarea> として編集していた(v1.36.0 のセクション単位の粒度)。ユーザー要望により、今や文書化されたスキーマから派生した構造化フィールドフォームをレンダリングする(career-ops.org Quick Start §Step-5): Target Roles / Adaptive Framing / Comp Targets追加/削除可能な反復ラベル付きライン入力(フィールドごとにロール/アングル/comp 1 行、+ Add line / 行ごとに aria-label 付き ); Exit Narrative / Location Policy → 単一のラベル付き散文 <textarea>。各フィールドは i18n セクション名を持つ <label htmlFor> で紐付けられた実コントロール。新しい public/js/lib/modes-form.js(window.ModesForm)が parse → render → collect() のロジックを保持する;これは既存PUT /api/modes/_profile { sections } マージ経路へ供給されるため、前文、順序、およびフォームが触れないすべてのセクションがバイト安定で残る(マージ-非置換、サーバー強制)。データ安全性: 本文が純粋な箇条書きでない正規リストセクション(ユーザーがそこに散文を入れた)および非正規 ## セクションは、説明ノート付きのラベル付きそのままの <textarea> にフォールバックする — 任意のコンテンツはそのまま round-trip し、決して暗黙に再構成されたり失われたりしない。Round-trip 安定性を実証:serialise(parse(body)) が同一に再パースされる。全ファイル生 markdown エディターは、セクションの追加/削除と前文編集のための確認ゲート付き Advanced ディスクロージャーとして残る(WS2 #4 破壊的保存ゲートは変更なし)。8 ロケール全体で新しい i18n キー 10 個(config.modesTargetRolesconfig.modesUnknownNote)。テストファイル tests/modes-form.test.mjs(7 ケース)を +1;725 → 732。隔離された CAREER_OPS_ROOT フィクスチャに対してライブ検証済み:正規セクション 5 個がフィールドとしてレンダリング + カスタムセクション 1 個がラベル付きフォールバックとして、編集して保存の round-trip が前文 + カスタムセクションを保持、コンソールエラー 0。feat(config) · test: tests/modes-form.test.mjs。詳細は CHANGELOG.md


[1.54.2] — 2026-05-18

feat(config): #/config の OpenAI / Codex モデルセレクター。 #/config には OpenAI / Codex モデルを選ぶ手段がなかった — OPENAI_API_KEY は親のマルチ CLI(Codex / OpenCode)フロー用に既に公開されていたにもかかわらず、ドロップダウンは ANTHROPIC_MODELGEMINI_MODEL にしかなかった。今や OPENAI_MODEL はファーストクラスの環境キー:env-config.mjsKNOWN_KEYS(OPENAI_API_KEY の直後に並べる)と core キーグループに追加し、SECRET_KEYS には意図的に含めない — 資格情報ではなくモデル id なので、決してマスクされない。config.js はキュレートされた OPENAI_MODELS リスト(デフォルト gpt-5-codex、続いて gpt-5 / gpt-5-mini / gpt-4.1 / o4-mini / o3)と、OpenAI キーの直後にレンダリングされる OPENAI_MODEL <select> フィールドを追加し、Anthropic/Gemini のモデルフィールドを正確に踏襲する。8 ロケール全体で新しい i18n キー config.openaiModel + config.openaiModelHint。テストファイル tests/openai-model-selector.test.mjs(4 ケース)を +1;721 → 725。ライブ検証済み:#/config → 6 オプションの OPENAI_MODEL select、デフォルト gpt-5-codex、ラベル紐付け済み、コンソールエラー 0。feat(config) · test: tests/openai-model-selector.test.mjs。詳細は CHANGELOG.md


[1.54.1] — 2026-05-18

fix(a11y): F-V54-A — #/cv を単一の <h1> に。 CV markdown 自身の # Name が、ページタイトルの <h1>CV</h1> の隣に 2 つ目 のトップレベル <h1> としてレンダリングされていた(回帰実行 F-V54-A;WCAG 1.3.1 情報と関係性 / 2.4.6 見出し)。cv.js は今や CV プレビューの全注入ポイント(初期レンダー、ファイルインポート時の更新、エディタのライブ同期)を、見出しを 1 レベル下げる(h1→h2 … h6→role="heading" aria-level="7")スコープ付きの cvMd() を通すようになり、ページは正確に 1 つの <h1> を保つ。cv.js に意図的にスコープ — UI.md は help/reports/deep/evaluate で共有され、それぞれが見出しを独自に管理するため。テストファイル tests/cv-single-h1.test.mjs(4 ケース)を +1;717 → 721。ライブ検証済み:#/cv<h1> 1 個、ユーザーの # Name は今や <h2>、コンソールエラー 0。fix(a11y): F-V54-A · test: tests/cv-single-h1.test.mjs。詳細は CHANGELOG.md


[1.54.0] — 2026-05-18

WS10 — canonical-docs 再検証 + help バンドルの H3 パリティ(最終の収束リリース)。 CHANGELOG/構造の CI ゲートは H2 しか検査していなかったため、docs/help/en.md は静かに 70 個の H3 サブセクションへ漂流した一方、7 つのローカライズ済みバンドルは 68 のままだった — ギャップは §17(「Reference adapters」テーブル + 「Common pitfalls」リスト、英語のみ)。両方が今や 7 言語すべてに翻訳され(アダプタのファイル名 / リンク / 識別子はバイト同一に保持);8 バンドルすべてが今 17 H2 / 70 H3。help-ru-config-section.test.mjs の新しい H3 パリティゲートがこれをロックする(716 → 717)。canonical-docs-coverage.test.mjs 7/7 が、help が依然として career-ops.org/docs の 5 ガイドすべてを反映していることを確認;WS2 の UX 監査(v1.41→v1.52 の 40 件)が各画面を docs と照合 — 乖離なし。docs/sdd/CONVENTIONS.md を v1.54.0 に更新(テスト合計、H3 パリティゲート、ファイルサイズの外れ値、新しいアクセシビリティ規約セクション)。WS0–WS10 完了;残るは WS11 のみ。fix(docs): WS10 canonical re-validation + H3 parity · test(help): H3-parity gate。詳細は CHANGELOG.md


[1.53.0] — 2026-05-18

WS9 — シェル表面のテストピラミッド(最後の未テスト層)。 4 つの bin/*.sh スクリプトと .githooks/pre-commit フックはカバレッジがゼロだった;新しい tests/sh-files.test.mjs が 10 件を追加し、bash -n/sh -n 構文、shebang + 実行ビット、そして他のワークストリームが依存する振る舞いの契約を固定する:career-ops-ui.shhelp は 0 で終了し shell-source の漏れがない(v1.40.0 リグレッションガード)、未知の verb は 2 で終了、usage() は heredoc;start.shNO_OPEN を尊重、Node ≥ 18 を要求、ブラウザの前面化を scripts/open-dashboard.mjs に委譲(v1.43.0 ガード);setup.sh — strict モード、SKIP_START、両リポジトリを clone;run_all.sh--quick/--no-e2e のパースと 4 スイート;.githooks/pre-commit は WS7 のレビュアを exec し、いかなるシェルファイルも git --no-verify を呼ばない(CLAUDE.md ハードルール #7 ガード);install-hooks.mjscore.hooksPath を配線する。docs/architecture/TESTING.md — ピラミッド図にシェル表面のベース層を追加 + v1.53.0 の合計ノート(716 node --test ケース / 90 ファイル + 4 E2E サーフェス)。706 → 716。詳細は CHANGELOG.md


[1.52.0] — 2026-05-18

WS2 LOWs #33–#40 — バッチ磨き上げ一掃(UX 監査キューを締める)。 低重大度の 8 件。fix(a11y/i18n): WS2 LOW batch — #33:#/dashboard — ヘッダーの 3 つの CTA が不揃いだった(2 つだけ先頭アイコンあり);「Open Pipeline」が今や 📋 を持ち、3 つすべてが揃う。#34:#/profile — アーキタイプの fit/level が曖昧な 2 つのチップとして描画されていた;今は接頭辞付き(Fit: / Level:)で対応する aria-label を持つ。#35:#/health — Run-doctor / verify の toast が doctor.mjs の生文字列を表示していた;今は i18n キー化。#36:#/health — チェック結果はフラットな <div> の連なりだった;今は role=list<ul>/<li> で、ステータスバッジは aria-label="<check>: <status>" を持つ。#37:#/reports — レポートカードはマウス専用の <div onClick> だった;今は role=link + tabindex + Enter/Space ハンドラ + aria-label。#38:#/activity — ページネータのコメントは「200」と言うがコードは 500 を要求していた;CAP 定数へ整合させ、500 上限が古い履歴を切り詰めると role=note の通知が現れる。#39:#/batch — プレースホルダ文言が英語ハードコードだった一方で aria-label は localized だった;4 つが今は i18n キー化。#40:モードページは非同期プローブ後に主ボタンを黙ってラベル変更していた;今は丁寧な role=status 領域がそれをアナウンスする。新規 i18n キー 10 件 × 8 ロケール({n} 保持);テスト +9:test: tests/low-sweep.test.mjs。697 → 706。WS2 の UX 監査キュー(v1.41→v1.52 の #1–#40)を締める;次は WS9 → WS10 → WS11。詳細は CHANGELOG.md


[1.51.0] — 2026-05-18

WS2 #13 + #14 + #18 + #19 + #20 — #/auto#/evaluate の feedback/i18n 一掃。 UX 監査の 5 件の指摘。fix(a11y/ux): auto+evaluate — busy state, actionable HTTP errors, clipboard fallback, aria-live result, spinner-guarded submit — #13:#/auto の Run ボタンは今や単に無効化されるのではなくビジー状態(is-loading + aria-busy +「Running…」)を表示する。#14:失敗した HTTP リクエストは今やステップ上の操作可能な i18n メッセージと toast({n} 付きの auto.httpFail)を提示する(以前は素っ気ない「HTTP 500」だった)。#18:手動モードの「Copy prompt」は今や非同期 Clipboard API を execCommand フォールバック付きで使い、偽の「Copied」ではなく実際の失敗を toast する。#19:evaluate の結果コンテナは今や role=status aria-live=polite であり、長い LLM 呼び出しがスクリーンリーダーへアナウンスされる。#20:Evaluate ボタンは UI.withSpinner でラップされた(以前は素の onClick: run で重複送信を許していた)。新規 i18n キー 3 件 × 8 ロケール;テスト +6:691 → 697。さらにテストのみの修正(コミット 7f8e250):e2e pipeline-delete のティアダウンが v1.48 以前のネイティブ confirm 経路上にあった;API DELETE へ切り替え(fix(test): … — CI の Playwright-e2e が赤だった;製品の回帰ではない)。詳細は CHANGELOG.md


[1.50.0] — 2026-05-18

WS2 #12 + #27 + #28 — help ナビゲーションのアクセシビリティ。 17 セクション・90+ 見出しのガイドにおける #/help の UX 監査の 3 件の指摘を help.js で修正。fix(a11y): help — single h1, labelled+filterable TOC, focus-on-anchor, back-to-top — #28:ドキュメントの markdown が独自の # Title で始まり、すでにヘッダーが正規の h1 を供給しているページに 2 つ目の <h1> を生んでいた;今は記事のすべての <h1> が除去され、h1 はちょうど 1 つで、階層は <h2> セクションから綺麗に始まる。#27:TOC の <nav> は名前の無いランドマークだった(ページ上にラベルの無い <nav> が 2 つ);今は aria-label(help.toc)を持ち、TOC エントリをクリックするとビューポートのスクロールだけでなくフォーカスがセクション見出しへ移る(tabindex=-1 + focus())。#12:長いドキュメント内で何かを見つける手段が無かった;TOC の上の type=search フィルタが見出しテキストでエントリをライブに絞り込み、スクロール後に aria-label 付きのフローティング「Back to top」ボタンが現れ、先頭に戻りページの <h1> にフォーカスを戻す;その scroll リスナーは #/help から離れる hashchange で除去される。新規 i18n キー 2 件 × 8 ロケール — help.tocFilterhelp.backToTop;テスト +6:test: tests/help-nav-a11y.test.mjs。685 → 691。詳細は CHANGELOG.md


[1.49.0] — 2026-05-18

WS2 #10 + #11 + #25 + #26 — tracker テーブルのアクセシビリティとソート。 #/tracker における UX 監査の 4 件の指摘を tracker.js で修正。fix(a11y): tracker headers, sortable table, localized fix labels, empty state — #10:アクション列のヘッダーは空文字列で、行ごとの Report ボタンには文脈が無かった;今はすべての <th>scope=col を持ち、アクションヘッダーと Score/PDF ヘッダーは i18n キー化され(空またはハードコードされた英語だった)、Report ボタンは会社名付きの aria-label(<report> — <company>)を得る。#11:ソート手段の無い tracker;Date / Score / Status ヘッダーは今や <th> 内のキーボード操作可能なソートボタンで aria-sort(none/ascending/descending)を持つ;sorted() コンパレータ(score は数値、date/status はロケール比較)がページネーションの前に走り、クリックで方向をトグルしページャをリセットする。#25:track.normalize/dedup/merge は最もリスクの高い破壊的コントロールであるにもかかわらず 8 ロケールすべてで同一の英語だった(data/applications.md をその場で書き換える)— 今は適切にローカライズされ、さらに title ツールチップを追加。#26:ゼロ行の初回実行が過剰フィルタのリストと同じ「no match」メッセージを表示していた;rows.length === 0 は今や独立した空状態(タイトル + 本文 +「Open pipeline」CTA)をレンダリングする。新規 i18n キー 7 件 × 8 ロケール + 3 件を再ローカライズ;テスト +6:test: tests/tracker-a11y-sort.test.mjs。677 → 683。詳細は CHANGELOG.md


[1.48.0] — 2026-05-18

WS2 #8 + #22 — pipeline:フォーカストラップされた確認 + プレビューのアクセシビリティ。 #/pipeline における UX 監査の 2 件の指摘を pipeline.js で修正。fix(a11y): pipeline UI.confirm() + live preview region — #8:#/pipeline の 3 つのアクションはネイティブ confirm() を使用していた(フォーカストラップされない):プレビューペインの Delete、行ごとの 削除、「Evaluate first」。いずれもフォーカストラップされる UI.confirm()(v1.44.0 のインフラ)を経由するようになった — 2 つの削除は danger:true(Cancel がデフォルト)、「Evaluate first」は danger:false;pipeline.js にネイティブ confirm() はもう残っていない。#22:previewPane にはライブロールが無く、fetch 失敗が previewBody に詰め込まれて誤解を招く <pre>「preview」としてレンダリングされていた;今は aria-label 付きの role=region aria-live=polite となり、失敗時は別の previewError を設定して独立した role=alert ブロックとしてレンダリングする((再)選択時およびアクティブ行の削除時にクリア)。新規 i18n キー 4 件 × 8 ロケール;テスト +5:test: tests/pipeline-confirm-preview.test.mjs。672 → 677。詳細は CHANGELOG.md


[1.47.0] — 2026-05-18

WS2 #7 + #30 + #31 + #16 — 未バインドラベルのアクセシビリティ一掃。 フォームコントロールにプログラム的ラベルが無かった UX 監査の 4 件の指摘(WCAG 1.3.1 / 3.3.2 / 4.1.2)を、すべてバインド。fix(a11y): bind every swept form control to an accessible name — #7 scan.js:dry-run チェックボックスと company-select ドロップダウンには for の無いラベルがあった;既存の id に合わせて htmlFor を追加。#30 deep.js:company / role 入力に未バインドのラベルがあった;id + htmlFor を追加(deep-companydeep-role)。#31 apply.js:url / jd に未バインドのラベルがあった;id + htmlFor を追加(apply-urlapply-jd)。#16 cv.js:主要な markdown <textarea> にアクセシブル名が無かった;表示されている「Markdown」見出しへ aria-labelledby でバインド — スクリーンリーダー名と画面上の見出しが一致、新規 i18n キーなし。batch.js / mode-page.js で既に標準の明示的 label[for]control[id] パターンを使用;新規 i18n キーなし;挙動の変更ゼロ。テスト +5:test: 667 → 672。詳細は CHANGELOG.md


[1.46.0] — 2026-05-18

WS2 #5 + #6 + #21 + #24 — scan SSE のアクセシビリティ。 #/scan における UX 監査の 4 件の指摘を scan.js で修正。fix(a11y): scan SSE — live-log region, Stop, run-state, error banner — #5:ストリーミングコンソールは今や role=log aria-live=polite(+ aria-labeltabindex=0、キーボードでスクロール可能)で、別の視覚的に隠された assertive な role=status 領域がターミナルイベント(完了 / 失敗 / 停止)をアナウンスする。#6:Stop ボタンが進行中の EventSource を閉じ(es.close())、結果ポーリングをキャンセルし、状態をリセットする。Stop は scan 実行中のみ表示。#21:scan 実行中は Scan ボタンを無効化 + aria-busy を付与し、Stop を表示する。両方のストリームパス(単一フェーズの streamTo と多フェーズの runScanAll — 後者は終端 donefinal !== false でのみ実行を終える)で適用。#24:SSE 障害はもはや 3.5 秒のトーストだけではなく、永続的な role=alert バナーがエラーを再試行アクション付きで表示(直近の実行関数を再呼び出し)し、次回の実行でクリアされる。i18n キー 8 件を新規追加 × 8 ロケール;テスト +7:test: tests/scan-sse-a11y.test.mjs。660 → 667。詳細は CHANGELOG.md


[1.45.0] — 2026-05-18

WS2 #3 — #/config タブ:完全な WAI-ARIA Tabs パターン。 #/config の 3 つのタブ(API keys / Profile / Modes)はクリックのみで起動する素の <button class="tab-btn"> で、rolearia-selected もキーボードモデルもなかった(UX-audit HIGH #3、WCAG 4.1.2 / 2.1.1)。fix(a11y): config.js tabs implement role=tablist/tab/tabpanel — 今は aria-label 付きの role=tablist コンテナ;各タブは role=tab + id + aria-controls + aria-selected(activate() 内で同期)+ ローテーション tabindex(アクティブ 0 / その他 -1);パネルは role=tabpanel + tabindex=0 + アクティブタブを追う aria-labelledby。完全なキーボードナビ:←/→/↑/↓(ラップ)+ Home/End がフォーカス移動と起動の両方を行う。レガシーの .tab-btn.is-active CSS フックは保持。i18n キー +1 × 8 ロケール(config.tablistLabel);テスト +7:test: tests/config-tabs-aria.test.mjs。さらにテストのみの修正:fix(test): retarget 2 stale auto-pipeline smoke tests — v1.34 以前の Playwright-e2e smoke テスト 2 件が、ダッシュボードの「Auto-pipeline」ボタンが v1.34.0 で開かなくなった一時モーダル(→ Router.go('/auto'))をアサートしており、別の Playwright-e2e CI ジョブで赤のままだった。#/auto 画面に再ターゲット。653 → 660。詳細は CHANGELOG.md


[1.44.0] — 2026-05-18

WS2 #4 + #9 — 親プロジェクトファイルの破壊的上書き前にフォーカストラップ付き確認。 UX 監査の HIGH が 2 件、いずれもデータ消失: (#4) config.jssaveProfileRaw/saveModesRaw は親の config/profile.yml / _profile.md を確認なしでまるごと置換していた; (#9) tracker.js の Normalize/Dedup/Merge は親の data/applications.md を確認なしでその場で書き換えていた。fix(a11y/safety): UI.confirm() gate before whole-file parent overwritespublic/js/api.js に新しい UI.confirm() を追加。既存の WAI-ARIA モーダル基盤を再利用したフォーカストラップ付きダイアログで(_onClose フックにより Esc / backdrop / × / Cancel のすべての解除経路が false を解決;フォーカスは既定で Cancel;Promise<boolean> を返す;ネイティブ confirm() ではない)、3 つの破壊的呼び出しはすべて書き込み前にゲートされる。新規 i18n キー 8 件 × 8 ロケール({op} プレースホルダは逐語的に保持);テスト +8:test: tests/confirm-gate.test.mjs、644 → 652。詳細は CHANGELOG.md


[1.43.0] — 2026-05-18

ユーザー要望 — career-ops-ui open + autostart によるブラウザ前面化。 setup/run の後、ブラウザが既に起動しているとむき出しの open/xdg-open ではダッシュボードのタブが背面に残り、ユーザーが探す羽目になっていた。feat(cli): career-ops-ui open — open AND raise the dashboard tab — 新しい scripts/open-dashboard.mjs が HOST/PORT から URL を構築し(0.0.0.0 バインドを loopback に書き換え)、必要なら /api/health を待ち、既定ブラウザを開いてから強制的に前面化する — macOS は osascript で起動中の Chrome/Brave/Edge/Safari/Arc/Firefox のいずれかをアクティブ化、Linux は xdg-open+wmctrl、Windows は startcareer-ops-ui open 動詞として公開(エイリアス dashfocus)。bin/start.sh の autostart はこれに委譲し、タブが自動的に前面化される;NO_OPEN=1 は headless/CI 起動で auto-open を無効化する。README ×8 + help §1 ×8 を更新;テスト +8:test: tests/open-dashboard.test.mjs、636 → 644。詳細は CHANGELOG.md


[1.42.0] — 2026-05-18

WS2 修正 #2 — デッドルート #/portals → config ディープリンク。 #/portals は未登録ルートで 404 ビューを描画していたが、ポータルソース管理用にブックマーク/手入力されうる妥当な URL だった(UX 監査 HIGH #2)。fix(router): #/portals 404 → alias to config + Regional-sources deep-linkrouter.jsALIASESportals: 'config' を追加(settings→profile と同じブックマーク安定化パターン)、これで config ビューに解決され config ナビ項目がアクティブになる。Regional-sources グループが存在する場合、ビュー(config.js)が #/portals ハッシュを検出し、その <details> グループを強制展開・スクロール表示し、その summary にフォーカスを移動(既定の h1 フォーカスを上書き)、ユーザーはポータルソース操作部にちょうど着地する;エイリアス単独で空の地域グループを描画することはない。help-bundle §5 × 8 にショートカット注記を追加;router テスト +1:test(router): portals→config alias guaranteerouter.test.mjs に追加、635 → 636。詳細は CHANGELOG.md


[1.41.0] — 2026-05-18

WS2 — シニア UX/ユーザビリティ監査 + 横断的フォーカス管理修正。 10 年以上のヒューリスティック監査(Nielsen × WCAG 2.2 AA × プロジェクト規約)で全 17 ルートを精査し、重大度順の 40 件キューを生成(.planning/.../UX-AUDIT.md);HIGH→MEDIUM→LOW をリリースごとに 1 修正ずつ出荷。本リリースは横断的 HIGH の第 1 位に着地。修正: fix(a11y): move focus to the new view on every route changerouter.js render() は hashchange ごとに #content を差し替えるがフォーカスを移動しなかったため、キーボード/スクリーンリーダー利用者が破棄されたノードに取り残され位置を失っていた(WCAG 2.4.3 Focus Order / 4.1.3 Status Messages — 横断的で全 17 画面に影響);新しい focusNewView(content) が新ビュー先頭の h1/.page-title にフォーカス(簡潔な SR アナウンス + 正しいフォーカス順)、必要なら見出しをフォーカス可能化(tabindex=-1)し #content にフォールバック;skip-link と競合しないよう初回描画はスキップ;成功・エラー両レンダパスに配線;ライブ検証済み:遷移後 document.activeElement は新ビューの H1.page-title。テスト: test(router): focus-management static guaranteesrouter.test.mjs に 4 ケース(ヘルパ定義、見出しターゲット + content フォールバック、初回描画スキップガード、≥2 呼び出し箇所);631 → 635。詳細は CHANGELOG.md


[1.40.0] — 2026-05-18

WS8.3 — docs 実態化スイープ + career-ops-ui help 修正 + askSecret 強化。 修正: fix(cli): career-ops-ui help no longer leaks shell source — ディスパッチャはヘッダコメントを sed -n '2,12p' で出力していたが、12 行目(set -euo pipefail)はコメントではなくコードのため、career-ops-ui help(および未知動詞の使用法テキスト)が余分な set -euo pipefail 行で終わっていた;help*) の両ケースを 2,11p(コメントブロック)に絞り込み;help は exit 0、未知動詞は exit 2 — 検証済み。fix(cli): scripts/init.mjs key entry never echoes — v1.39.0 のフォローアップで装飾的な readline 上書きマスクを実際の raw モードリーダに置換: setRawMode(true) + バッファ行により、入力/貼り付けされたキーのバイトが端末に一切届かない(scrollback / tmux / 画面共有への漏洩なし);完全な VT エスケープ FSM が CSI/SS3/OSC/DCS/SOS/PM/APC の全シーケンスを消費し、矢印・ファンクションキーが秘密を破損しない;stdin は依存性注入されるため、非 TTY フォールバックはグローバルを触らず単体テスト;AI レビュー LGTM までクリーンに反復。ドキュメント: README ×8 — 旧「ワンコマンドインストール」セクションを目立つ 「ワンコマンドで起動と初期化」 セクションに置換(curl ワンライナーに加え明示的な career-ops-ui CLI チェーン: clone → npm linksetupinitdoctorrunhelp、プロバイダウィザード説明、CI 形式 --provider --anthropic-key --yesLLM_PROVIDER ノート);8 つの README バッジを v1.22–v1.24 / tests-461–474 から v1.40.0 / tests-631 に実態化(e2e バッジは捏造カウント回避のため非数値化);help-bundle ×8 §1 — クイックスタート手引きの先頭(「A. Setup」の前)に「ワンコマンド起動 & init」コールアウトを 8 ロケール全てに追加;H2 セクションのパリティ維持(各 17 — CI ゲート緑)。テスト: test(init): non-TTY askSecret fallbackprovider-selector.test.mjs に DI-stdin ケースを追加し、askSecret が非 TTY で共有グローバルを変更せず素の ask() に委譲(trim パリティ)することを検証;629 → 631。詳細は CHANGELOG.md


[1.39.0] — 2026-05-18

WS8.2 — LLM プロバイダ選択 + OpenAI/Codex キー + 対話型 init ウィザード。 env-config に LLM_PROVIDER(auto|claude|gemini)+OPENAI_API_KEY(秘匿)。llm.mjs の 6 ゲートが _provGate() 経由で providerOrder() を参照;auto は挙動不変。#/config に select+フィールド。scripts/init.mjs は実ウィザード(検証済みパスで parent .env 書込)。7 テスト。622 → 629。README ×8/正規ドキュメント fold = WS8.3/WS10。詳細は CHANGELOG.md


[1.38.0] — 2026-05-17

WS8.1 — 統合 CLI ディスパッチャ + doctor 動詞。 bin/career-ops-ui.sh が setup/run/doctor/init/help をルーティング。scripts/doctor.mjs/api/health エンジンをそのまま再利用(createApp インプロセス → ターミナルレポート);必須チェック全通過時のみ exit 0。docs/sdd + help §1 ×8。6 テスト。616 → 622。README ×8 = WS8.3。詳細は CHANGELOG.md


[1.37.0] — 2026-05-17

WS7 — git ワークフローの pre-commit AI レビュー。 決定論フロア(fail-HARD):staged .env/シークレット、diff 内キーパターン、staged ビューの .also(node --check 失敗をブロック。AI レイヤ(fail-SOFT):CLI があり AI_REVIEW != off なら claude -p.githooks/pre-commit + preparecore.hooksPath を配線。--no-verify 禁止。docs/sdd。6 テスト。610 → 616。詳細は CHANGELOG.md


[1.36.0] — 2026-05-17

WS6.3 — Modes タブ:生の塊 → セクション別エディタ。WS6 完了。 modes/_profile.md## セクション単位で編集(見出しごとに折りたたみ textarea)。サーバ splitProfileSections はバイト厳密;PUT { sections } は指定セクションのみマージ — プリアンブル・他セクション・順序をバイト単位で保持。未知見出し → 400。raw 経路は不変。i18n 5 キー ×8。help §2 ×8。新規テスト 6。604 → 610。WS6 完了。詳細は CHANGELOG.md


[1.35.0] — 2026-05-17

WS6.4 — Profile 配列エディタ + WS6.2 API-keys 監査。 PUT /api/profile{ arrays } を受理({ fields } と併用可):Target roles/Superpowers(リスト)、Archetypes(name/level/fit)、Proof points(name/url/hero-metric)。同一 merge-not-replace;空行破棄;空リストはキー削除。#/config に add/remove エディタ 4 つ。i18n 6 キー ×8。監査:KNOWN_KEYS ≡ FIELDS、ギャップなし。新規テスト 7。597 → 604。詳細は CHANGELOG.md


[1.34.0] — 2026-05-17

WS5 — ワンクリック Auto-pipeline 画面(#/auto)。 モーダルを専用・リンク可能ページへ昇格。ワンクリックで検証→取得→評価→レポート保存→トラッカー(SSE)。アクセシブルなステッパー、ディープリンク、キーなし手動モード、#/auto?url=…&go=1 リンク可。サイドバー項目;ダッシュボード ✨ ボタンはここへ。i18n 14 キー ×8。help §1 ×8 + README ×8。新規テスト 8。589 → 597。詳細は CHANGELOG.md


[1.33.0] — 2026-05-17

WS4 — career-ops 1.8.0 パリティ監査 + location_filterscan.mjslocation_filter(#570)追加;web-ui の in-process スキャナは委譲しないため流れず。新 server/lib/location-filter.mjs がセマンティクスを忠実に複製、両スキャナに配線。help §5 ×8。新規テスト 8。581 → 589。詳細は CHANGELOG.md


[1.32.0] — 2026-05-17

#/config Profile タブ — 生 YAML 塊 → 項目別フォーム (WS1)。 折りたたみ 3 セクション(候補者/ナラティブ/報酬)、14 スカラーパス。項目保存は config/profile.ymlマージ — アーキタイプ・プルーフポイント・独自キーをそのまま保持。Advanced に raw-YAML エスケープハッチ維持(コメント保持)。i18n 23 キー ×8。新規テスト 7。574 → 581。詳細は CHANGELOG.md


[1.31.0] — 2026-05-17

career-ops 1.8.0 同期 — #/batch--model + --start-from を公開。 親プロジェクトが 1.7.1 → 1.8.0 に。batch-runner.sh--model NAME(#504)+ --start-from N 追加。web-ui は #/batch で公開(モデル開始 # 入力)+ サーバ側 defense-in-depth 検証。i18n ×8。新規テスト 7。567 → 574。詳細は CHANGELOG.md


[1.30.0] — 2026-05-14

#/scan 結果ページネータ — v1.12 の「最初の 200 件を表示 / 合計 N」トランケーションを置き換え。

v1.30 以前は、スキャン結果テーブルがフィルタ後の最初の 200 行で切り詰められ、「Showing first 200 of N」のフッターが表示されていました。201..N 行は UI から到達不能。v1.30.0 はキャップを UI.paginate に置換します(#/tracker / #/reports / #/activity と同じヘルパー)。PAGE_SIZE = 200 で従来の視覚密度を維持;ブースト先頭の並びがページ間で安定(全体をソート後にページ分割);フィルタ変更時にページ 1 に自動リセット。未使用の scan.shownTop i18n キーを削除(8 ロケール)。tests/scan-paginator.test.mjs に 9 件の新規ケース(静的カナリア 7 件 + 6 つの境界ケースを持つ純ロジックテーブル 1 件 + サマリ計算 1 件)。558 → 567 unit + acceptance(+9)。完全な詳細は CHANGELOG.md を参照。


[1.29.2] — 2026-05-14

ホットフィックス:🌐 Scansource=both で実行しても EN フェーズのみ動作。RU フェーズが静かに破棄されていました。

SSE クライアント(public/js/api.js:156)が最初の done イベントで EventSource をクローズしていましたが、サーバは source=both でフェーズごとに 1 つずつ送出します。RU フェーズは開始直後にキャンセルされていました。修正:サーバは各 donefinal: true|false を付与し、クライアントは final !== false の場合のみクローズします。後方互換 — final を設定しない単一フェーズの送出側は従来通りクローズ。547 → 558 unit + acceptance(+11 新規)。完全な詳細は CHANGELOG.md を参照。


[1.29.1] — 2026-05-14

5 つの RU ポータルを構成するための詳細なユーザガイドを help-bundle §5 の 8 ロケール全てに追加。

§5(Portals & sources)内に新規 ### サブセクション「ロシア系ポータルの構成 — 詳細セットアップガイド」を追加:認証・地域制限を含む 5 ソースのインベントリ表、portals.yml の場所と編集手順、5 ソースの YAML 例、negative リストの衝突と修正例、1 ソースを一時無効化する方法、🌐 Scan + SSE ログによる検証方法。§17(v1.29.0 で出荷)は開発者向けフロー、§5 v1.29.1 はエンドユーザ向けフロー。540 → 547 unit + acceptance(+7 新規)。完全な詳細は CHANGELOG.md を参照。


[1.29.0] — 2026-05-14

ロシア系ポータルスキャナが 2 → 5 ソースに拡張。レジストリ + 動的ドロップダウン。新 §17「新規ポータルの追加方法」。

  • 3 つの新 RU アダプタ: Trudvsem(政府オープンデータ API、認証なし、ジオゲートなし)、GetMatch および GeekJob(防御的な HTML スクレイプ — パース失敗時は []、健全な 200 で throw しない)。
  • ソースレジストリ server/lib/sources/registry.mjs — ディスパッチャ + エンドポイント + ドロップダウンが消費する単一情報源。v1.29 以前は 3 箇所にハードコードされていました。
  • 新エンドポイント GET /api/scan/sources(Cache-Control: max-age=60) — SPA は #/scan マウント時にソースフィルタのドロップダウンを動的に再構築。
  • 新規 §17 8 ロケール全てに「新しい求人ポータルソースを追加する方法」(アダプタテンプレート、レジストリエントリ、ディスパッチャ、モックテスト、portals.yml)。
  • russian_portals.sources のデフォルト["hh", "habr"] から 5 ソースに変更。portals.ymlsources: を明示的に列挙している場合は、新規 3 つを手動で追加してください。
  • テスト: 520 → 540(+20)。完全な詳細は CHANGELOG.md を参照。

[1.28.1] — 2026-05-14

ホットフィックス: ?query 付きハッシュでの router 404。health から HH_USER_AGENT 行を削除。

v1.28.1 以前は Router.go('/evaluate?url=…') が最初の split('/') セグメントとして "evaluate?url=…" リテラルを生成し、登録済みルートに一致せず __not_found__(404)に落ちていました。1 行修正: 名前分割の前に hash.split('?')[0]。報告された 2 つのクリックを両方カバーします:#/pipeline → ▶ と「App settings → Modes」。オプションの HH_USER_AGENT 行は /api/health から削除(ロシア外 403 ゲートのヒントは help-bundle §16 に残り、スキャン時に stderr でも依然として出力される)。515 → 520 unit + acceptance(+5 新規)。完全な詳細は CHANGELOG.md を参照。


[1.28.0] — 2026-05-14

ドキュメント整合 + #/batch--max-retries N コントロール。qa/QA-PROMPT-docs-vs-app.md から提起された 2 件のオープン issue を解消します。

  • Issue #2#/batch に数値入力「Max retries」(1–10) を追加。「Retry failed」がチェックされた場合のみ有効化。サーバ側で parseInt と 1≤N≤10 のレンジ検証を行い、範囲外は静かに破棄、--retry-failed なしで --max-retries は付与されません。tests/batch-max-retries.test.mjs の 7 ケース。新規 i18n キー 2 個 × 8 ロケール。
  • Issue #1 — 8 個の help-bundle と 8 個の README の AI CLI リストを career-ops.org/docs の正典(Claude Code・Codex・OpenCode・Qwen CLI)に揃え、ローカライズされた一文を追記:「同じスラッシュコマンド・サーフェスで他の Claude 互換 CLI も動作します」。README の「Multi-CLI」項目(web-ui 自身の shim ファイル説明)はそのまま(別 surface)。tests/canonical-docs-coverage.test.mjs に新規カナリア 2 個。
  • 506 → 515 unit + acceptance(+9 新規)。Playwright 32/32 変更なし。完全な詳細は CHANGELOG.md を参照。

[1.27.0] — 2026-05-14

外観 + アクセシビリティ調整: サイドバーの #/dashboard エントリ重複排除。

サイドバーで、ブランドロゴ(<a class="logo" href="#/dashboard">)と最初のナビ項目が同一ルートを指していました。スクリーンリーダーは「Dashboard」を二回読み上げ、キーボード操作で無意味なタブストップが発生していました。ブランドブロックは通常の <div class="logo"> になり、ナビ項目のみが #/dashboard への唯一のリンクとなります。506 / 506 unit + 32 / 32 Playwright — 変更なし。詳細は CHANGELOG.md を参照。


[1.26.1] — 2026-05-14

ホットフィックス WCAG 2.5.5 — .btn 最小高さ 44 px の復元.

v1.26.0 で .btnmin-height: 44px 宣言が失われ、ヘッダーボタンが 39-41 px で描画されていました (WCAG 2.5.5 違反)。v1.26.1 で 44 px のフロアと flex-shrink: 0 + line-height: 1.2 を復元。502 → 506 unit、Playwright 32/32 変更なし。詳細は CHANGELOG.md を参照。


[1.26.0] — 2026-05-14

テストピラミッド + 行カバレッジ ≥ 93 %.

v1.25 バックログに従い 4 階層テストピラミッド (unit → functional → acceptance → e2e) を導入。v1.25 で最大だったカバレッジギャップを埋める 22 件の新テスト (jds.mjs 61.64 % → 100 %、auto-pipeline 拒否経路)。マルチエンドポイントのユーザージャーニーテスト用に tests/acceptance/ ディレクトリを新設。480 → 502 unit + acceptance、Playwright 32/32 変更なし。詳細は CHANGELOG.mddocs/architecture/TESTING.md を参照。


[1.25.0] — 2026-05-14

自動パイプラインの手動ショートサーキット + ダッシュボードのコスメティック修正 + CHANGELOG パリティのバックフィル。 G-014 (自動パイプラインが mode: 'manual' を無視していた問題)、G-012 (CHANGELOG パリティのドリフト — 6 ロケールが 2 リリース遅れていた)、およびダッシュボードの ✨ ✨ 二重グリフのコスメティック問題をクローズします。G-003 (README.cn.md のリネーム) は実質的に既にクローズ済み — リポジトリには README.zh-CN.md しか存在しません。G-005 (A-G → A-F レポートブロックの再整列) は親プロジェクトとの協調コミットが必要で、引き続き延期となります。

🛡️ G-014 — 自動パイプライン mode: 'manual' ショートサーキット

  • fix(auto-pipeline): G-014 — honour mode:'manual' short-circuit (server/lib/routes/auto-pipeline.mjs:158-195) — v1.25 以前は、このルートは常に LLM を呼び出していました。mode: 'manual' を渡す (v1.10.2 以降の /api/evaluate のミラー) は黙って無視され、リクエストは Anthropic で 1〜3 分ハングしていました。新ハンドラの動作は以下の通りです:
    • 後方互換のため modeevalMode の両方を受け付けます。いずれかが 'manual' であればショートサーキットが発動します。
    • 5 ステージ全ての SSE を status: 'done' / status: 'skipped' で送出します。fetch なし、LLM 呼び出しなし、リクエストあたり $0.05 のコストなし。
    • done ペイロードは { mode: 'manual', prompt: <buildEvaluationPrompt scaffold>, message } を含み、SPA は既存の /api/evaluate 手動プロンプトカードと同様にレンダリングできます。
  • HOST=0.0.0.0 における DoS リスクをクローズ: 以前は llmRateLimit が 10 req/60s/IP で上限を設けていたとしても、攻撃者 10 名 × 各 10 リクエスト = 1 分あたり $50 の Anthropic 課金が発生していました。ショートサーキットは実呼び出しのレート制限カウントが減る前に発火します。
  • テストtests/auto-pipeline-manual-mode.test.mjs: 3 件のテストで以下を確認します — (1) mode: 'manual' が 5 ステップキー全てを伴って 2 秒以内に返ること、(2) ANTHROPIC_API_KEY がセットされていてもショートサーキットが発火すること (元の症状)、(3) レガシーな evalMode: 'manual' 呼び出し元が引き続き動作すること。

📝 G-012 — CHANGELOG パリティのバックフィル (6 ロケール × 欠落 2 リリース)

  • docs(changelog): backfill v1.23.0, v1.24.0, v1.24.1, v1.25.0 in 6 lagging locales — v1.25 以前は EN のみが v1.23-v1.24 を持ち、RU は 1 リリース遅れ、その他 6 ロケールは 2 リリース遅れでした。v1.25 では並列翻訳エージェント (v1.23 と同じパターン) をディスパッチし、4 エントリ全てを CHANGELOG.{es,pt-BR,ko-KR,ja,zh-CN,zh-TW}.md に投入します。RU は v1.24.0 + v1.24.1 + v1.25.0 を受け取ります (v1.23.0 は v1.23 サイクルで既に翻訳済み)。
  • feat(ci): scripts/check-changelog-parity.mjs gate — いずれかのロケール CHANGELOG の最新エントリが EN 正本より古い場合、ビルドを失敗させます。npm run test:ci に組み込み済み。既存の G-012 ドリフトは、EN の境界を越えた瞬間に自身を検出できていたはずです。

✨ コスメティック — ダッシュボードの二重グリフ重複排除

  • fix(dashboard): dedup ✨ glyph in auto-pipeline button label (public/js/lib/i18n-dict.js:219) — dash.autoPipeline は全ロケール文字列の先頭に を含んでおり、加えて public/js/views/dashboard.js:58 がビュー側でさらに を前置していました。結果、ボタンは ✨ ✨ Auto-pipeline … とレンダリングされていました。v1.25 では各ロケール DICT エントリの先頭グリフを削除し、ビューの前置を唯一のソースとします。同じ監査パスで残りの i18n バンドルもスイープしましたが、他に二重グリフのパターンは見つかりませんでした。

🚫 将来のリリースへ延期

  • G-005 — 正規 career-ops.org/docs に従ったレポートブロック A-G → A-F — 親プロジェクト santifer/career-ops の協調コミットが必要 (modes/oferta.md を書き換えて A=Role、B=CV-match、C=Strategy、D=Comp、E=Personalization、F=STAR を出力し、C-Risks / G-Legitimacy を独立ブロックから外す)。v1.25.0 は web-ui 側を新スキーマ受け入れ可能な状態で出荷します (reports.js は v1.13 以降、任意のブロック文字を受け付けます)。親と子を一緒に着地できる次のリリースウィンドウまでトラックします。
  • G-003 — README.cn.mdREADME.zh-CN.md リネーム — v1.25 準備時に検証済み: リポジトリには既に README.zh-CN.md のみが存在し (worktree 配下に孤児の README.cn.md は皆無)。G-003 の指摘は陳腐化していました。

🧪 テスト

  • 477 → 480 ユニットテスト (+3 は PR-B の auto-pipeline-manual-mode.test.mjs より)。
  • 32/32 Playwright は変更なし。
  • npm run test:cinpm test + check-no-also-leftovers.mjs + check-changelog-parity.mjs を実行するようになりました。

検証

$ npm run test:ci
# 480 / 480
# ✓ no .also( leftovers in views/
# ✓ CHANGELOG parity: all 8 locales at v1.25.0

# G-014 — manual mode returns < 2 s even with ANTHROPIC_API_KEY set:
$ ANTHROPIC_API_KEY=sk-ant-test PORT=4317 npm start &
$ sleep 3
$ time curl -sS -X POST -H 'Content-Type: application/json' \
    -d '{"url":"https://job-boards.greenhouse.io/anthropic/jobs/x","mode":"manual"}' \
    http://127.0.0.1:4317/api/auto-pipeline | head -20
# real  0m0.1xx s  (was 1-3 min)
# event: start … event: step (×5) … event: done {"mode":"manual","prompt":"…"}

# G-012 — every locale CHANGELOG carries the v1.25.0 entry:
$ grep -c '^## \[1.25.0\]' CHANGELOG*.md
# 8 files, each → 1

# Cosmetic — dashboard glyph:
$ grep "dash.autoPipeline" public/js/lib/i18n-dict.js
# No leading ✨ in any locale value (view supplies the single glyph)

破壊的変更

なし。mode: 'manual' はオプトインで、レガシーな evalMode: 'manual' 呼び出し元は変更なしで引き続き動作します。

スコープ外 (v1.26+)

項目 備考
G-005 — A-F レポートブロックの再整列 親プロジェクトの協調コミットが必要 (santifer/career-opsmodes/oferta.md を書き換え)。
QA シナリオ 31 の ビジュアル サブテストのライブ実行 ブラウザ駆動エージェント (Claude Cowork) が必要。Playwright スモークで部分的にカバー。
i18n-dict.js の 400-LOC 目標超過 翻訳フィクスチャ — ポリシーにより除外。バンドラを使わずに分割すると HTTP リクエストが増えるため不採用。

[1.24.1] — 2026-05-14

ホットフィックス: 8 ロケール全てで #/config がクラッシュ (G-015)。

🚑 重大ホットフィックス

  • fix(config): G-015 — replace removed Element.prototype.also call in config.js (public/js/views/config.js:371) — v1.22.0 の N-2 で Element.prototype.also のグローバルモンキーパッチを撤去し、cv.js をフリーステートメントパターンへ移行しましたが、config.js の移行が漏れていました。結果、#/config は全ロケールで初回呼び出し時に c(...).also is not a function を伴ってクラッシュしていました。v1.24.1 では cv.js:188-201 と同じ移行パターンを適用 — ツリーを const root = c(...) に抽出し、起動ブロックを単体で実行した後 return root; を返します。

🛡️ CI ゲート

  • feat(ci): scripts/check-no-also-leftovers.mjs sweeppublic/js/views/ 配下の全ファイルを走査し、いずれかの .also( 呼び出しサイト (コメント内参照は許可) があればビルドを失敗させます。新しい npm run test:ci スクリプトに組み込み済み。将来モンキーパッチ撤去がリバートされても、同じリグレッションが黙って再導入されることはありません。

🧪 テスト

  • test: tests/config-view-syntax.test.mjs — 3 つのガード:
    • node:vm.Scriptconfig.js をパース (Playwright なしでも構文レベルのリグレッションを捕捉)
    • コメント外に .also( が残っていないことを表明
    • const root = c(...) / return root; の移行アンカーが存在することを表明
  • 474 → 477 ユニットテスト (+3) + 32/32 Playwright は変更なし。

検証

$ npm run test:ci
# 477 / 477
# ✓ no .also( leftovers in views/

# Browser smoke:
$ open http://127.0.0.1:4317/#/config
# → renders normally, no "is not a function" card. Every locale equivalent.

スコープ外 (v1.25 に延期)

  • G-014, G-012, G-005, G-003 — バンドルは下方の v1.25.0 エントリを参照してください。

[1.24.0] — 2026-05-14

ヘルプバンドルのコンテンツ深度リフレッシュ + QA シナリオ 31 のライブ実行 + RU CHANGELOG のエンドツーエンド翻訳。 v1.23.0 の「スコープ外」テーブルで v1.24 に延期された 2 項目を両方クローズします: 5 本の正規 career-ops.org/docs URL から 8 言語ヘルプバンドル全ての本文を深度リフレッシュ (v1.11.x 以降は URL カバレッジのみだった)、および稼働中サーバに対する QA シナリオ 31 のライブ実行 (“ブラウザエージェント + LLM 認証情報が必要” としていたが、6/6 サブテストのうち curl + grep で到達可能で、ビジュアルサブテストのみブラウザが必要と判明)。

📖 ヘルプバンドルのコンテンツ深度リフレッシュ

  • docs(help): refresh en.md from 5 canonical career-ops.org/docs URLs (docs/help/en.md) — v1.24 以前は EN バンドルは 1113 行で、フロントマターに 5 本の正規 URL を列挙していましたが、本文では展開していませんでした。v1.24 では WebFetch で 5 URL 全てを取得し、対応する H2 セクションを深堀りします:
    • About career-ops (フロントマター) — 原則 (データ主権、AI 非依存、人間が制御) を追加、“What career-ops is NOT” ブロック追加、コンセプト一覧を 6 → 10 行に拡張 (Proof points、JD store、Interview-prep、Batch additions を追加)。
    • §5 Portals — 正規ブートストラップ cp templates/portals.example.yml portals.yml を追加、tracked_companies エントリ毎の必須/任意フィールドを明確化。
    • §7 Scan — Option A に「AI トークンを消費しない」注記を追加、後続コマンドリスト (apply / contacto / deep / tracker) を追加。
    • §14 Apply checklist — SPA チェックリストモード vs Manual-vs-Playwright-assisted vs Full CLI フロー (/career-ops apply <company> から Submitted. までの正規 8 番号ステップ、Evaluated → Applied 自動遷移付き) に分割; バッチ評価サブセクションに TSV スキーマテーブル + 4 フラグ全ての記載 + merge-tracker.mjs --dry-run を追加; Playwright Setup サブセクションにインストールコマンド、MCP 登録、代替 .claude/settings.local.json、デフォルトでのヘッドレス注記を列挙。
  • 16-H2 セクションパリティを維持 (CI テスト help-ui.test.mjs::section-parity が全 8 ロケールで H2 セクションが厳密に 16 個であることを表明)。
  • 5 本の正規 URL がそれぞれバンドル内に 2 回以上出現 (CI テスト canonical-docs-coverage.test.mjs が強制)。v1.24 後の URL 毎の出現回数: what-is-career-ops × 4、scan-job-portals × 5、apply-for-a-job × 3、batch-evaluate-offers × 5、set-up-playwright × 3。
  • docs(help): translate the v1.24 deepening to 7 non-EN locales — 7 つの並列翻訳エージェントをディスパッチ。各ターゲットロケール (es / pt-BR / ko-KR / ja / ru / zh-CN / zh-TW) は EN 構造をセクション毎に反映したリフレッシュバンドルを受け取り、コードブロック / URL / ファイルパス / ボタンラベル (📁 Upload CV / 🌐 Scan now / ▶ Evaluate / 📄 Generate PDF / 💾 Save) と英語略語 (CSP, SSRF, TOCTOU, WCAG, ATS, JD, SSE, REST, API) は原文のまま保持し、深化部分はターゲット言語のパブリケーション品質のネイティブ技術スタイルに翻訳します。

🧪 QA シナリオ 31 — ライブ実行 (6/6 PASS)

  • docs(qa): append last-verified live-execution log to qa/claude-cowork-browser-test-prompt.md — v1.24 以前のシナリオ 31 はドキュメント化されていたものの、稼働中サーバに対して未実行 (“ブラウザエージェント + LLM 認証情報が必要” として延期)。v1.24 では 6 つのサブテスト全てを http://127.0.0.1:4317 に対して実行しました:

    Sub 説明 ステータス
    31.1 ヘルプバンドル内のスコア閾値 ✅ PASS (docs/help/en.md 内で 4.5 × 3、4.0 × 9、3.5 × 6 言及)
    31.2 スキャンワークフローのエンドポイント ✅ PASS (/api/stream/scan-{en,ru} + /api/scan-ru/config → 404; /api/scan/regional/config → 200)
    31.3 /api/apply-helper チェックリスト ✅ PASS (本文に career-ops apply + auto-submit 警告を含む)
    31.4 /api/batch エンドポイント ✅ PASS (キー [exists, runnerExists, raw, rows, additions])
    31.5 Playwright の可用性 ✅ PASS (/api/healthPlaywright (parent node_modules) ok: true, value: installed を報告)
    31.6 ヘルプバンドル URL カバレッジ (5 URL × 8 ロケール) ✅ PASS (40 / 40 ✓)

    ビジュアル専用サブテスト (ブラウザを必要とする) は QA プロンプトで個別にフラグ — 引き続き Claude Cowork または npm run test:e2e:browser で実行可能。

🌐 RU CHANGELOG エンドツーエンド (M-9 フォローアップ)

  • docs(translate): CHANGELOG.ru.md retry agent — full body translation (CHANGELOG.ru.md) — v1.23.0 リリースは RU CHANGELOG リトライエージェントが進行中のまま出荷されました (一度ソケットエラーでクラッシュし、再ディスパッチされていた)。v1.24 ではエージェントの 1542 行に及ぶフル翻訳を取り込みます: v1.23.0 → v1.6.0 までの全エントリがパブリケーション品質のロシア語本文を持ち、EN 本文の応急処置は撲滅されました。スタイル規律は v1.22.0 README 品質リフレッシュと同等: 不格好な “функционал” は “функциональность” / “возможности” / “поведение” に置換; “при помощи” は “через” / “с помощью” に置換; 受動態より能動態優先; “эндпоинт”、“レート制限”、“競合状態”、“サニタイズ” を正規用語として採用; 英語略語 (TOCTOU, CSP, SSRF, WCAG, ATS, JD, SSE, REST, API) は原文保持。

🧪 テスト

  • 474 / 474 ユニット + 20 / 20 スモーク E2E + 32 / 32 Playwright。挙動テストのデルタはゼロ; ヘルプバンドルの CI 表明 (16 H2 セクション × 8 ロケール、5 URL × ≥ 2 言及、コンテンツフロア) は全てグリーンを維持。

検証

$ npm test                            # 474 / 474

# Help-bundle deepening:
$ wc -l docs/help/en.md
# ~1270 lines (was 1113 — deepened, not bloated)

$ for url in what-is-career-ops scan-job-portals apply-for-a-job \
             batch-evaluate-offers set-up-playwright; do
    echo -n "$url: "
    grep -c "$url" docs/help/en.md
  done
# what-is-career-ops: 4
# scan-job-portals: 5
# apply-for-a-job: 3
# batch-evaluate-offers: 5
# set-up-playwright: 3

# Scenario 31.6 — 40/40 URL coverage:
$ for lang in en es pt-BR ko ja ru zh-CN zh-TW; do
    echo -n "$lang: "
    for url in what-is-career-ops scan-job-portals apply-for-a-job \
               batch-evaluate-offers set-up-playwright; do
      curl -sS "http://127.0.0.1:4317/api/help/$lang" \
        | python3 -c "import sys,json; print(json.load(sys.stdin).get('markdown',''))" \
        | grep -q "$url" && echo -n "✓ " || echo -n "✗ "
    done
    echo
  done

破壊的変更

なし。

スコープ外 (v1.25+)

項目 備考
シナリオ 31 の ビジュアル サブテストのライブ実行 ブラウザ駆動エージェント (Claude Cowork または npm run test:e2e:browser) が必要。curl のみの実行ではスコープ外で、既存の Playwright スモークでカバー。
旧エントリ (v1.5.x 以下) の RU CHANGELOG 本文翻訳 リトライエージェントは v1.6.0 以降のみカバー。v1.6 より前のエントリ (v1.5.x 等) — 仮に存在していたとしても — 既存コンテンツのまま。
今後の SPA 変更後のダッシュボードスクリーンショットのビジュアルリグレッション scripts/capture-dashboard-screenshots.mjs がロケール毎の PNG を再生成; 現状自動 diff なし。

[1.23.0] — 2026-05-14

i18n 分割 + 接続バナー CI 修正 + ロケール別ダッシュボードスクリーンショット + 全バックログの応急処置クローズ。 v1.22.0 の「スコープ外」テーブルで v1.23 にフラグされた 3 項目 (M-9 ロケール CHANGELOG 本文、N-1 i18n.js LOC 分割、ヘルプバンドルコンテンツ監査) に加え、v1.22.0 後の main ブランチ CI をレッドにしたスモーク E2E テストへのホットフィックスを出荷します。

🚑 CI ホットフィックス — 接続バナーリカバリ

  • fix(client): reset health-poll cadence + visibilitychange eager re-check (public/js/api.js:21-91) — v1.22.0 の M-6 指数バックオフは正しい設計 (3 秒 → 6 秒 → 12 秒 → 上限 15 秒、元の上限 60 秒から低下) でしたが、進行中の setTimeout は直前に設定された delay にロックされていました。t=0.1 でサーバが kill され、最初の ping が t=3 で失敗すると delay は 6 へ倍化し、次の復旧プローブは t=9 まで発火しません。スモーク E2E の「Flow 2a: connection banner appears on server down, hides on recovery」は 4 秒しか待たず、main でレッドに転じました。

    v1.23.0 はポーリングループを再構築します:

    • _healthHandle を追跡することで setConnectionState(lost=true)clearTimeout を呼び、_HEALTH_MIN で再スケジュールできるようにしました。最初の復旧プローブは、キューに積まれた delay に関係なくダウンから 3 秒以内に発火します。
    • _HEALTH_MAX を 60 秒から 15 秒に低下。デッドサーバに対してバックグラウンドのタブはユーザが戻ったとき 1 ポーリングサイクル内で復旧し、帯域節約も維持されます。
    • document.addEventListener('visibilitychange') でタブがフォーカスを取り戻し connectionLost === true のときに即時再チェック — Cmd-Tab で戻る際に次のバックオフティックを待ちません。

🧹 N-1 — i18n.js 分割 (400-LOC 目標超過)

  • refactor(client): split DICT into i18n-dict.js (data) + i18n.js (logic) — v1.23 以前は public/js/lib/i18n.js が 639 LOC。大部分 (23-586 行) は DICT 翻訳テーブル — 純粋な構造化データでした。v1.23.0 ではこれを public/js/lib/i18n-dict.js に抽出 (578 LOC、CLAUDE.md の「これらの制限から除外: 生成ファイル、マイグレーション、テストフィクスチャ、ロックファイル、ベンダーコード」により LOC ルールから除外 — 翻訳テーブルはフィクスチャに該当)、public/js/lib/i18n.js はピュアなモジュールロジック 86 LOC (400-LOC 目標を十分下回る) に。
  • ローダー契約: i18n-dict.jswindow.__I18N_DICT = { … } を投入し、続いて i18n.js が既存の IIFE 内でそれを読み取ります。public/index.htmli18n-dict.jsi18n.js より先に読み込むため、IIFE は構築時に完全に投入された DICT を見ます。Missing-dict フォールバック: 各 t() 呼び出しはインラインフォールバックまたは素のキーを返し、SPA をクラッシュさせずに誤設定を明示的に表面化します。
  • テスト配管の更新: tests/i18n-coverage.test.mjstests/help-ui.test.mjstests/canonical-docs-coverage.test.mjs は両ファイルをテスト VM コンテキストで実行 (または regex スイープ用にソースを連結) するようになり、既存の全表明を維持します。

🌐 M-9 — ロケール CHANGELOG 本文翻訳

  • docs(translate): 7 non-EN CHANGELOG files end-to-end — v1.23 以前は CHANGELOG.{es,pt-BR,ko-KR,ja,ru,zh-CN,zh-TW}.md は v1.13.0 以降の各エントリで EN 本文の応急処置注記を保持し、フッタは読者を EN 正本に誘導していました。v1.23.0 では 7 並列翻訳エージェント (ロケール毎 1 つ) をディスパッチし、全ての本文をターゲット言語のパブリケーション品質の技術スタイルで書き直します。応急処置注記は撤去。コードブロック、ファイルパス、URL、コミットメッセージスタイル文字列 (fix(security): B-1 — …)、環境変数、リンクラベルは全ロケールで原文のまま保持します。

🖼️ 全 README にロケール別ダッシュボードスクリーンショット

  • docs(readme): wire each locale README at its locale-specific PNG — v1.23 以前は README.pt-BR.md のみが dashboard-pt-BR.png を参照し、その他 6 つの非英語 README は依然として dashboard-en.png を指していました。スクリーンショット (v1.22.0 サイクルで scripts/capture-dashboard-screenshots.mjs によって既に撮影済み) は images/ 配下に存在しましたが未使用でした。v1.23.0 では各 README.{es,ja,ko-KR,ru,zh-CN,zh-TW}.md の 14 行目を自身の dashboard-<locale>.png に更新します。

🧪 テスト

  • v1.22.0 と同じ 474 / 474 ユニット + 32 / 32 Playwright。スモーク E2E は 20 / 20 (v1.22.0 後の main ではバナーリカバリのリグレッションで 19 / 1 失敗していたが、v1.23.0 の再スケジュール修正で解消)。
  • 既存テスト 3 件を i18n 分割に対応すべく再配線。新規テストファイルゼロ、削除した表明ゼロ。

検証

$ npm test
# 474 / 474

$ npm run test:e2e
# passed: 20    failed: 0    (was 19/1 on v1.22.0 main)

$ wc -l public/js/lib/i18n.js public/js/lib/i18n-dict.js
#       86 public/js/lib/i18n.js          ← logic, under target
#      578 public/js/lib/i18n-dict.js     ← data fixture, exempt

$ grep -h 'dashboard-' README*.md | sed -E 's/.*(dashboard-[^)]+).*/\1/' | sort -u
# dashboard-en.png    (README.md only)
# dashboard-es.png    dashboard-ja.png
# dashboard-ko-KR.png dashboard-pt-BR.png
# dashboard-ru.png    dashboard-zh-CN.png  dashboard-zh-TW.png

# CHANGELOG translation sanity: each locale file > 200 lines of native content
$ wc -l CHANGELOG.{es,pt-BR,ko-KR,ja,ru,zh-CN,zh-TW}.md | grep -v total

破壊的変更

なし。public/index.html は従来 1 つだったところで 2 つのスクリプトを読み込むようになりました — CDN から SPA を配信する場合は i18n-dict.js を取り込む必要があります; スクリプト読み込み順序は index.html 内の <script src> タグの順序で強制されます。新ファイル欠落時のランタイムフォールバック (空 DICT → t() がインライン EN フォールバックを返却) でハードクラッシュを防止します。

スコープ外 (v1.24+)

項目 備考
career-ops.org/docs に対するヘルプバンドル CONTENT 深度リフレッシュ (URL カバレッジ vs) 5 本の正規 URL は v1.11.x 以降全ロケールのヘルプバンドルに既に出現しており、QA プロンプトのシナリオ 31.6 がカバレッジを検証。コンテンツ本文の深度リフレッシュは v1.24+ の候補。
稼働中サーバに対する QA シナリオ 31 のライブ実行 ブラウザエージェント + ライブ LLM 認証情報が必要。v1.24 候補。
新規モードページのヒント段落に対する部品単位のタッチターゲットスイープ v1.22.0 M-1 で追加された <p class="field-hint"> 要素は全 8 ロケールで WCAG 2.5.5 最小高さに対する検証が未実施。

[1.22.0] — 2026-05-14

M/L/N バックログの一括解消 + ドキュメント整合性 + 翻訳品質向上パス。 v1.20.1-BACKLOG.md の medium 以下の項目を 1 リリースで全てシップしました: M 項目 9 件、L 項目 5 件、nit 2 件。加えて 5 本の正規ガイド career-ops.org/docs に対するドキュメント整合性監査、.claude/.github/ 配下のシステムプロンプト刷新、英語以外 7 ロケール全ての README 品質リフレッシュ。

🛡️ セキュリティ強化 (多層防御)

  • fix(security): M-4 — entity-aware stripDangerousMarkdown (server/lib/security.mjs) — v1.22 以前の正規表現は <script>javascript:on*= をリテラル部分文字列として照合していました。&lt;script&gt;java&#115;cript:<img src="data:image/svg+xml,<svg onload=…>"> は通り抜けていました。サニタイズ処理は strip 正規表現を走らせる &lt;&gt;&amp;&quot;、数値参照 (&#NN;)、16 進参照 (&#xHH;) をデコードするようになりました。tests/cv-xss-bypasses.test.mjs の 11 件のテストで検証済みです。実際の防御はクライアント側の UI.md の escape-first パイプラインが担いますが、本修正はディスク上のファイルそのものを堅牢化します。

  • fix(security): L-2 — bash --noprofile --norc on the batch runner (server/lib/routes/batch.mjs:108) — spawn('bash', [PATHS.batchRunner, ...]) はユーザーの ~/.bashrc を継承していました。悪意ある rc ファイルが実行に影響を及ぼし得ます。現在は spawn('bash', ['--noprofile', '--norc', PATHS.batchRunner, ...])

🔒 レジリエンス

  • fix(client): M-6 — exponential backoff on health ping (public/js/api.js:22-48) — disconnected 状態のポーラーは停止したサーバーに対し一晩で 28,800 回の fetch を発火していました。現在は 3 秒 → 6 秒 → 12 秒 → 24 秒 → 60 秒、最初の 2xx 回復で 3 秒にリセット。各ステップが新しい遅延を読み取れるよう、setInterval ではなく setTimeout チェーンで構成しています。

  • fix(client): M-5 — Safari private-mode localStorage guard (public/js/lib/i18n.js:572-583) — Safari のプライベートモードでは localStorage.getItem/setItem の度に SecurityError がスローされます。ロード時の IIFE が i18n モジュール全体を失敗させ、SPA が生のキー文字列をレンダリングする状態に陥っていました。両方の呼び出しを try/catch でラップし、detect() によるブラウザ言語フォールバックに切り替えました。

  • fix(server): M-2 — body-size cap on outbound preview fetches (test + verify) — v1.21.0 の safeGet は既にチャンクをストリーミングし opts.maxBytes で上限を設けていました。v1.22 では契約をロックするための回帰テストを tests/ssrf-redirect-rebind.test.mjs に追加: 上流 100 KB + 4 KB 上限 → レスポンス ≤ 4 KB。

  • fix(client): L-5 — clear setTimeout on hashchange in scan.js (public/js/views/scan.js:6-22, :113-120) — done 後の 300 ms refreshResults() タイマーは、そのウィンドウ内にユーザーが #/scan から離脱するとリークしていました。ハンドルを捕捉し __cancelActiveScanPoll でクリアするようになりました。

  • fix(client): L-4 — multi-line SSE data: joiner (public/js/lib/auto-pipeline.js:158-176) — SSE パーサーは match() (単一行) を使っていました。仕様上、イベントは複数の data: 行を持つことができ、コンシューマーは \n で結合します。サーバーは現在単一行 JSON しか送っていないため旧コードは動作していましたが、将来の複数行ペイロードに対して脆弱でした。

♿ アクセシビリティ

  • feat(a11y): M-3 — WCAG 1.4.1 redundant cues on score pills + connection banner (public/css/app.css:602-625, :812-822) — score-high / score-mid / score-low は色相 (赤/琥珀/緑) だけで状態を伝えていました。色相を知覚できないユーザーには代替手段がありませんでした。各階層は ::before 経由で冗長なグリフ (✓ / ◐ / ○) を持つようになりました。Connection banner はオフライン状態で先頭に グリフを表示します。レンダリングサイトは無変更 — 純粋な CSS による堅牢化です。

  • feat(a11y): M-1 — inline hint paragraphs for every mode-page field (public/js/views/mode-page.js, public/js/lib/i18n.js) — v1.20.0 では mode-page の全フィールドに htmlFor → id を配線しましたが、インラインのヒントコピーは持ち越されず、README ウォークスルーだけがフィールドの意図を文書化していました。v1.22.0 は 19 件のヒント i18n キー × 8 ロケール = 152 件の新規翻訳 を追加し、field() ビルダーがフィールド毎に <p id="…-hint"> をレンダリングして aria-describedby を配線します。スクリーンリーダーユーザーは入力フォーカス時にヒントを聞くことができます。

  • fix(a11y): M-7 — null-guard on UI.el() htmlFor alias (public/js/api.js:194-198) — htmlFor: null はリテラル for="null" をレンダリングしていました。フォールスルー分岐の v != null && v !== false ガードを 1 行ミラーしただけの修正です。

🧹 品質 / ポータビリティ

  • fix(server): L-1 — parseInt radix in health.mjs + bin/start.sh + bin/setup.shparseInt(process.versions.node) の radix 省略は lint 警告を発し、Node が将来 16 進バージョンを出荷した場合に脆弱です。全箇所に 10 を付与しました。

  • fix(server): L-3 — Windows-safe entrypoint check (server/index.mjs:159-163) — import.meta.url === \file://${process.argv[1]}` は Windows のドライブレターとバックスラッシュを誤処理します。fileURLToPath(import.meta.url) === path.resolve(process.argv[1])` に置換しました。

  • refactor(client): N-2 — drop Element.prototype.also monkey-patch (public/js/views/cv.js:188-201) — グローバル DOM プロトタイプ汚染。ツリールート用のローカル変数に置換しました。

  • test(canary): M-8 — 404 regression test for retired /api/scan-ru/config (tests/scan-consolidated.test.mjs) — v1.20.0 で alias を撤去しましたが canary が無い状態でした。v1.18 の撤去テストをミラーする 3 行追加です。

📚 ドキュメント + システムプロンプト

  • docs(architecture): refresh OVERVIEW + DATA-FLOWS for v1.21+ surface — OVERVIEW.md に safe-fetch.mjs (DNS ピン留め GET)、file-lock.mjs (パス別ミューテックス)、rate-limit.mjs (LLM スロットル)、sanitizePathName を追加。DATA-FLOWS.md には新たに 2 セクションを追加: “Outbound URL fetches (DNS-rebind-safe)” と “LLM endpoint rate-limiting”。

  • docs(readme): security envelope section refresh — README.md の “Security notes” は v1.21+ セキュリティエンベロープの全ヘルパー (sanitizePathName、safeGet、withFileLock、llmRateLimit、entity-aware stripDangerousMarkdown) を文書化するようになりました。

  • docs(qa): scenario 31 — career-ops.org/docs alignment (qa/claude-cowork-browser-test-prompt.md) — 5 本の正規 career-ops.org/docs ガイドで記述された挙動と UI が一致することを検証する 6 個の新サブテスト (31.1–31.6): スコア閾値、scan ワークフロー (ボタン 1 つ)、apply ワークフロー (チェックリスト、自動送信ではない)、batch ワークフロー (TSV エディタ)、Playwright セットアップ (graceful failure)、help バンドル網羅 (URL 5 件 × ロケール 8 件)。

  • docs(translate): README quality refresh × 7 non-EN locales — 英語以外の全 README をネイティブ言語で出版品質の技術文体に書き直し。よくある不自然な calque を置換、v1.21/v1.22 のセキュリティエンベロープへの言及を追加、release/test バッジを更新。

  • docs(system): .claude/PROJECT-CONTEXT.md + .github/copilot-instructions.md — セッションに参加するエージェント向けの 1 ファイル方向付け。CLAUDE.md を圧縮し、v1.21+ のヘルパーを列挙し、よくある落とし穴を記載。

  • docs(bin): actualize start.sh / setup.sh / run_all.sh comments — “two deps” → “three deps” (express + js-yaml + multer);“298 tests” → “474+ tests”;parseInt radix の追加。

🧪 テスト

  • 461 → 474 unit (+13) + 32/32 Playwright は変更なし。
  • 新規テストファイル: cv-xss-bypasses.test.mjs (M-4、11 テスト)。
  • 拡張: ssrf-redirect-rebind.test.mjs (+1 for M-2 body cap)、scan-consolidated.test.mjs (+1 for M-8 alias canary)。
  • 既存スイートにおける挙動上のテスト差分はゼロ — 全ての修正は追加的、もしくは新規 canary でカバーされます。

検証

npm test                          # 474 / 474
npm run test:e2e:browser          # 32 / 32

# Entity-encoded XSS strip:
node -e "import('./server/lib/security.mjs').then(({stripDangerousMarkdown}) => console.log(stripDangerousMarkdown('&lt;script&gt;alert(1)&lt;/script&gt;')))"
# → '' (no <script> survives)

# Health-ping backoff (open devtools, kill server, watch network panel):
#   3 s → 6 s → 12 s → 24 s → 60 s, then resets on first successful ping

# Score-pill glyph (open #/reports in light + dark theme):
#   .score-high shows ✓ + numeric score
#   .score-mid  shows ◐ + numeric score
#   .score-low  shows ○ + numeric score

# Mode-page hints (#/contacto, etc):
#   <input aria-describedby="mode-contacto-recipient-hint">  ← targets <p id="…">

# Retired alias:
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:4317/api/scan-ru/config
# → 404

破壊的変更

ありません。全ての修正は追加的か、既存のエンドポイント契約を保ちます。

スコープ外 (v1.23+)

項目 ノート
M-9 — ロケール CHANGELOG 本文翻訳 CHANGELOG.{es,pt-BR,ko-KR,ja,ru,zh-CN,zh-TW}.md の v1.13+ エントリは EN-bodied の応急処置でした。リリースペース鈍化後に一括翻訳の候補。
N-1 — public/js/lib/i18n.js が 400 LOC 目標を超過 ロケール別分割はバンドラ無しでは HTTP コストが増加します。build-step 判断確定まで保留。
career-ops.org/docs からの help バンドル内容刷新 5 本の正規 URL は (v1.11.x 以降) 全ロケールの help バンドルに既出。QA プロンプトの Scenario 31.6 が網羅を検証。内容深度の刷新は v1.23 の候補。

[1.21.0] — 2026-05-14

2 つの独立したコードレビューパスから得たセキュリティ + 同時実行性 + a11y のポリッシュ。 docs/specs/V1.20.1-BACKLOG.md の 7 件の指摘を 1 リリースでシップ: ブロッカー 1 件 (DNS リバインド TOCTOU)、高重大度バグ 6 件 (path-traversal サニタイズの分散、LAN デプロイにおけるレート制限の欠落、書き込みの競合状態、i18n カバレッジの穴、宙ぶらりんな aria-describedby、label 関連付けの欠落)。新規テスト 34 件;ベースラインは 427 → 461 unit + 32/32 Playwright に上昇。全ての修正には名前付きの回帰テストが伴います。

🛡️ セキュリティ

  • fix(security): B-1 — close DNS-rebind TOCTOU via safe-fetch.mjs (server/lib/safe-fetch.mjs) — 従来のパターンは検証用に 1 度明示的な dnsLookup を行い、その後 fetch() に独立した別のルックアップを許していました。TTL=0 の DNS リバインド攻撃者は 1 回目のルックアップで公開 IP を返し、2 回目のルックアップで 127.0.0.1 / 169.254.169.254 / LAN アドレスを返すことで isPrivateOrLoopbackHost を回避できました。新しい safeGet は名前解決を 1 度だけ行い、node:http(s) 経由で TCP 接続をその IP にピン留めし、証明書検証が元のホスト名を対象とするよう SNI/Host を設定します。/api/pipeline/preview/api/auto-pipeline で使用。ルックアップエラー時は fail-CLOSE (以前の try { … } catch { /* fall through */ } を反転)。tests/ssrf-redirect-rebind.test.mjs の 8 件の新規テストで検証済み。

  • fix(security): H-4 — consolidate sanitizePathName across 10 routes (server/lib/security.mjs) — jds.mjscontent.mjsreports.mjsllm.mjsrunners.mjs にまたがる素の replace(/[^\w\-.]/g, '') 正規表現は重複しており、. 文字を保持していたため ..pdf....md、先頭ドット名が通り抜けていました。正しく実装されていたのは reports.mjs::sanitizeSlug のみ。v1.21.0 は正しい版 (sanitizePathName) を security.mjs に集約し、壊れた 10 個のコピーを削除し、空結果を 400 で拒否します。tests/path-traversal.test.mjs の 12 件のテストで検証済み。

  • fix(security): H-5 — rate-limit LLM endpoints on public bind (server/lib/rate-limit.mjs) — /api/evaluate/api/deep/api/mode/:slug/api/auto-pipeline には IP 別のスロットルがありませんでした。ループバックユーザーには影響なし;LAN 公開デプロイ (HOST=0.0.0.0) はオーバーフロー時に Retry-AfterX-RateLimit-* ヘッダ付きで 10 req/min/IP を取得します。LLM_RATE_LIMIT="N/Ws" で構成可能。v2.0 P-12 の auth ゲートに先行する廉価な暫定防御です。tests/rate-limit.test.mjs の 6 件のテストで検証済み。

🔒 同時実行性

  • fix(data): H-6 — per-file mutex on applications.md / pipeline.md (server/lib/file-lock.mjs) — 同時の POST /api/tracker (もしくは auto-pipeline と手動追加の競合) は両方が num=42 を読み、両方が num=43 を書き、先行する行をサイレントに失っていました。withFileLock(path, fn) はパス毎に read-modify-write を直列化します;独立したパスは並列実行を維持します。tracker.mjspipeline.mjs (POST + DELETE)、auto-pipeline.mjs の tracker ステップに配線。tests/concurrent-tracker-write.test.mjs の 5 件のテストで検証済み (20 並列 POST の統合チェックで 001..020 が逐次定着することをアサート)。

♿ アクセシビリティ

  • fix(a11y): H-1 — id="batch-tsv-hint" on the batch.js hint paragraph (public/js/views/batch.js) — v1.20.0 は TSV textarea に aria-describedby="batch-tsv-hint" を追加したものの、ヒントの <p> に対応する id を付けていませんでした。スクリーンリーダーは何も読み上げるものがありませんでした。修正済み。

  • fix(a11y): H-2 — htmlFor on batch-parallel / batch-min-score labels (public/js/views/batch.js) — v1.20.0 で 4 つの input が新しい id を取得しましたが、ラベルがプログラム的に関連付けられていませんでした。WCAG 3.3.2 を満たすようになりました。

  • 新規 tests/a11y-form-wires.test.mjs の静的解析 canary — 全 view ファイルを走査し、各 aria-describedby / htmlFor IDREF が兄弟の id: 宣言を指していることをアサートします。CI 時にタイポ系回帰を検出します。

🌐 i18n

  • fix(i18n): H-3 — 13 keys from v1.20.0 silently fell through to EN for 7 locales (public/js/lib/i18n.js) — pipe.filterpipe.countpipe.preview*pipe.openTabpipe.evaluateAll*eval.jdHintbatch.parallelAriabatch.minScoreAria、加えて common.deleteconfig.group{Core,Runtime,Regional}config.profileEmptyconfig.viewProfilescan.atsBadgescan.regionalBadget('key', 'EN fallback') 経由で参照されていましたが DICT には追加されていませんでした。ロシア語・日本語・中国語のスクリーンリーダーユーザーは英語の aria-label を聞いており、これは v1.20.0 が主張した WCAG 3.3.2 の勝利を直接打ち消していました。v1.21.0 は 19 キー × 8 ロケール (約 150 件の新規翻訳) を追加し、tests/i18n-coverage.test.mjs に静的解析パスを拡張して public/js/**/*.js 内の全ての t('key', …) 呼び出しを走査し各キーが DICT に存在することをアサートします。将来のドリフトは CI 時に検出されます。

🧪 テスト

  • 427 → 461 unit (+34) + 32/32 Playwright は変更なし。
  • 新規テストファイル: ssrf-redirect-rebindpath-traversalconcurrent-tracker-writerate-limita11y-form-wires
  • 既存の pipeline-preview.test.mjsglobalThis.fetch モックから safe-fetch.mjs の新しい _setTransport 注入ポイントへ配線変更 — SSRF パスはもう fetch を通らないため、旧モックはサイレントにバイパスされていました。

検証

npm test                              # 461 / 461
npm run test:e2e:browser              # 32 / 32
node --test tests/ssrf-redirect-rebind.test.mjs tests/path-traversal.test.mjs \
  tests/concurrent-tracker-write.test.mjs tests/rate-limit.test.mjs \
  tests/a11y-form-wires.test.mjs      # 34 new tests, all green

# Path-traversal: every traversal-style :name returns 400 / 404
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:4317/api/jds/..pdf
# → 400

# Rate-limit on public bind:
HOST=0.0.0.0 LLM_RATE_LIMIT=3/60s npm start &
for i in 1 2 3 4; do
  curl -sS -o /dev/null -w '%{http_code} ' -X POST -H 'Content-Type: application/json' \
    -d '{"jd":"…"}' http://0.0.0.0:4317/api/evaluate
done
# → 200 200 200 429

# Concurrent tracker writes: 20 parallel POSTs, 20 rows land:
node tests/concurrent-tracker-write.test.mjs
# 20 sequential rows 001..020

# Aria wires sanity:
grep -r 'aria-describedby' public/js/views/ | wc -l
# matching `id:` lookups all resolve (a11y-form-wires.test.mjs canary)

スコープ外 (v1.22+)

項目 ノート
pipeline-preview のボディサイズ ストリーミング上限 (M-2) await upstream.text() は 8 KB スライス前に全ボディを読みます;悪意ある 1 GB ストリームでメモリが枯渇し得ます。バイトカウンタ + abort でストリーム読みに。
WCAG 1.4.1 — .connection-banner + スコアピルでの色のみによる状態表現 (M-3) 色相のみが状態を示しています;アイコン接頭 (✓ / ◐ / ○) もしくはテキスト接尾を追加。
stripDangerousMarkdown の HTML エンティティ経由のバイパス (M-4) &lt;script&gt;java&#115;cript:<img src="data:image/svg+xml,<svg onload=…>"> は正規表現を通り抜けます。UI.md による多層防御は引き続き有効;ドキュメント化 + テストスイープでバイパスをロック。
Safari プライベートモードの localStorage アクセスを try/catch 無しで実行 (M-5) i18n.js:544/571 がスロー → SPA が生キーをレンダリング。try/catch で 'en' デフォルトにラップ。
setInterval(checkHealth, 3000) がバックオフ無しで永久ポーリング (M-6) 指数的 3 秒 → 6 秒 → 12 秒 → 上限 60 秒。
htmlFor alias の null ガード欠落 (M-7) 1 行の if (v != null && v !== false) 防御。
撤去された /api/scan-ru/config 用 404 canary (M-8) v1.18 の前例をミラーする 3 行テスト。
ロケール CHANGELOG 本文翻訳 (M-9) リリースペース鈍化後の一括翻訳候補。
全 mode-page フィールドのインラインヒント段落 (M-1) 約 168 i18n キー × 8 ロケール;ポリッシュ項目として保留。
L-1 〜 L-5 の nit parseInt radix、bash –noprofile、Windows-safe fileURLToPath、複数行 SSE、scan.js タイマークリーンアップ。

[1.20.0] — 2026-05-13

コンポーネント別 a11y ポリッシュ + 英語以外 README パリティ + /api/scan-ru/config alias 撤去。 v1.19.0 の “Out of scope” 表で v1.20 向けに挙げられていた 4 項目をクローズします。

♿ WCAG 2.5.5 / 2.5.8 — コンポーネント別タッチターゲット監査

  • a11y(touch-target): chip min-height 28 px + 8 px gap (2.5.8 spaced-target exception).chip は 24 × 約 50 px (垂直 24 でクラスタリングされたコントロール向けの 2.5.5 の 24 px フロアを満たさず);2.5.8 の spaced-target 例外は ≥ 24 × 24 px もしくは 24 px のクリアランスを要求します。.chipmin-height: 28px; padding: 6px 12px; に、ラップする .chip-rowgap: 8px; に引き上げ、両条件を満たすようにしました。
  • a11y(touch-target): sidebar nav-item min-height 44 px.nav-item10px 14px のパディングのみで、ほとんどのビューポートで算出高 約 36 px。現在は padding: 12px 14px; min-height: 44px; box-sizing: border-box;.btn のフロアと一致します。
  • a11y(touch-target): tab-btn min-height 44 px — Reports、Tracker、Scan results にまたがる Sortable Headers / カテゴリタブにも同じ処理。

♿ WCAG 1.3.1 / 3.3.2 — インラインフォームヒントの aria-describedby

SPA の全フォームコントロールは安定した id を持ち、<label>htmlFor で対象を指し、インラインヒント段落は aria-describedby で関連付けられるようになりました。5 つの view ファイルが配線変更されました:

  • a11y(forms): config.js — キー毎の id + ヒント関連付け (cfg-<key> / cfg-<key>-hint)。
  • a11y(forms): evaluate.jseval-jd textarea + サニタイズ後の 50 文字最小を文書化する eval-jd-hint 段落。
  • a11y(forms): batch.jsbatch-tsv / batch-tsv-hint、加えて batch-parallelbatch-min-scorebatch-dry-runbatch-retry への aria-label
  • a11y(forms): pipeline.jspipe-filter + pipe-new-url / pipe-new-url-hint
  • a11y(forms): mode-page.js — 7 つの汎用 mode (projecttrainingfollowupbatch-promptcontactointerview-preppatterns) にまたがる全フィールドが mode-<slug>-<name> の id と htmlFor ラベルを取得。

UI.el() は React 形式の htmlFor alias を学習し、view コードが宣言的でいられるようになりました — 内部では for 属性 (JS 上はプロパティ名として予約) に設定します。

🌍 英語以外 README パリティ

  • docs(readme): translate 7 locales to 585-line parity with EN masterREADME.{es,pt-BR,ko-KR,ja,ru,zh-CN,zh-TW}.md は 306〜316 行 (見出しは網羅していたがマーケティング重視のウォークスルーと API リファレンスのほとんどはスキップ) でした。7 ロケール全てが EN 構造を端から端までミラーします: About → One-command install → Why? → Quick start (3 段階) → Requirements → What you get テーブル → Scan → Architecture (完全なディレクトリツリー) → API リファレンス (全ルートテーブル) → Tests → Configuration → Security notes → Limitations → Contributing → 🌍 Getting Started 5 段階ウォークスルー → License。

🧹 /api/scan-ru/config alias 撤去

  • feat!(scan): remove /api/scan-ru/config legacy alias (sunset v1.20) — v1.19 で 1 リリース分の後方互換 alias として残されていました。正規の /api/scan/regional/config のみがパスとして残ります。削除: server/lib/routes/scan.mjs のルート登録、README.mddocs/architecture/{OVERVIEW,SERVER,API}.md のドキュメント参照。テストは既に正規パスをカバーしていたため変更不要。

🧪 テスト

  • v1.19 と同じスイート。427 / 427 unit + 20/20 smoke + 23/23 comprehensive + 32/32 Playwright。全ての a11y 配線は追加的 (id / for / aria-describedby の追加) — 挙動変更なし、テスト差分なし。

検証

npm test                              # 427 / 427
npm run test:e2e:browser              # 32 / 32

# Touch targets — every chip / nav-item / tab-btn ≥ 28 / 44 / 44 px:
#   Chrome DevTools → Computed → height/min-height on .chip, .nav-item, .tab-btn

# Form labels — every input has a label[for=…] association:
#   document.querySelectorAll('input,textarea,select').forEach(el =>
#     console.assert(el.labels?.length || el.getAttribute('aria-label'), el))

# Alias gone:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:4317/api/scan-ru/config
# → 404

# Canonical still works:
curl -s http://127.0.0.1:4317/api/scan/regional/config | jq '.'

破壊的変更

  • DELETE /api/scan-ru/config — 削除。/api/scan/regional/config を使用してください。v1.19.0 の CHANGELOG と検証スクリプトで sunset 告知済み。

スコープ外 (v1.21+)

項目 ノート
全 mode-page フィールドのインラインヒント段落 今は <label for=…> 関連付けのみ;可視のフィールド毎ヒントコピーは SPA では依然 EN のみ。README ウォークスルーが各ロケールでフィールド意図を文書化しているため、ブロッカーではなくポリッシュ項目です。
.connection-banner とダッシュボードスコアピルにおける色のみの状態表現 (WCAG 1.4.1) バナーは赤/琥珀/緑に依存;色相を知覚できないユーザー向けにアイコンかテキスト接尾が必要。
ロケール別 CHANGELOG 本文翻訳 CHANGELOG.{es,pt-BR,ko-KR,ja,ru,zh-CN,zh-TW}.md には英語本文の応急処置が残ります。v1.x リリースペース鈍化後に翻訳実施。

[1.19.0] — 2026-05-13

WCAG 1.4.3 コントラスト + scan 統合 (最終) + UI から HH_USER_AGENT 削除。 v1.18 のスコープ外コントラスト監査をクローズし、v1.18 で始めた EN/RU 分割排除を完了し、ユーザー指示により UI から HH_USER_AGENT 構成ノブを削除します (サーバーに同梱された妥当なデフォルトが既にほとんどのユーザーの非 RU IP を処理します)。

♿ WCAG 1.4.3 コントラストパス

  • a11y(contrast): introduce AA-passing *-text variants for accent tokens — ライトテーマ: --rausch-text: #b80f42 (白上で 6.59:1、旧 3.52:1)、--kazan-text: #066507 (7.31:1、旧 4.53:1)、--darjeeling-text: #7a5800 (琥珀背景で 5.73:1、旧 4.24:1)、--babu-text: #00665e (6.09:1、旧 2.70:1)。ダークテーマ: 明色化されたミラー (#ff8aa0#6ee7b7#fcd34d#5eead4) が #161a22 ペーパー上で同じ 4.5:1 フロアに到達。
  • バッジクラス (.badge-ok.badge-warn.badge-bad.badge-info) とスコアピル (.score-high.score-mid.score-low) は新しい *-text バリアント経由でルートされ — text-on-tinted-bg の全組み合わせが AA を通過します。アクセント塗りつぶしトークン (--rausch--kazan 等) はボーダー・アウトライン用にそのまま維持 (非テキスト UI コンポーネントは 3:1 のみ必要)。

🧹 Scan 統合 (v1.18 作業の完了)

  • docs(scan): scrub remaining EN/RU split references across READMEs + help + architecture docs — README 8 本 + help バンドル 8 本 + アーキテクチャドキュメント 3 本 (API.md、SERVER.md、OVERVIEW.md、DATA-FLOWS.md) + scan.js コメントが、単一の統合された scan メソッドを記述するようになりました。レガシー /api/stream/scan-{en,ru} alias は v1.18 で既に削除済み;v1.19 はスキャンを EN+RU の 2 段階プロセスとしてフレーミングしていた残りのドキュメント/コピーを補足します。
  • feat(scan): canonical /api/scan/regional/config endpoint/api/scan-ru/config は後方互換のため 1 リリース分の薄い alias として保持。新パスは source 命名規約 (?source=regional) と一致します。

🛠️ UI から HH_USER_AGENT 削除

  • feat!(config): drop HH_USER_AGENT field from /#/config + KNOWN_KEYS — パワーユーザーは引き続き career-ops/.env で直接 HH_USER_AGENT を設定可能 (サーバーは server/lib/sources/hh.mjsprocess.env.HH_USER_AGENT を読み、同梱 UA をフォールバック)。UI が公開しなくなったのは、デフォルトがほとんどのユーザーで機能し、App Settings ページの不可解な User-Agent フィールドが繰り返し混乱の原因となっていたためです。
  • README × 8 ロケール + help バンドル × 8 ロケールの言及を “run via a Russian IP / VPN” 助言に置換。scan.hhWarning i18n キーは env-var セットアップ詳細を落として書き直し。
  • KEY_GROUPS を縮小: regional 分類なし (HH_USER_AGENT しか含んでいませんでした)。テスト更新;SPA 後方互換のため regionalActive ペイロードフィールドは保持。

🧪 テスト

  • tests/env-config.test.mjsKNOWN_KEYS のアサートが HH_USER_AGENT を除外するように;キーが意図的に欠落していることをアサートする新規追加。
  • tests/config-endpoint.test.mjs — POST-write 複数キーテストが HH_USER_AGENT の代わりに 2 番目の既知キーとして GEMINI_MODEL を使用。
  • tests/config-groups.test.mjsgroups.HH_USER_AGENTundefined 期待。
  • 合計: 427 / 427 unit + 20/20 smoke E2E + 23/23 comprehensive E2E + 32/32 Playwright。全ての調整済みテストは既に計上済みのため v1.18.0 と同じ数。

検証

npm test                              # 427 / 427

# Contrast (Chrome DevTools or axe) on light + dark:
#   .badge-ok / .badge-warn / .badge-bad / .badge-info → AA pass (4.5:1+)
#   .score-high / .score-mid / .score-low → AA pass

# HH_USER_AGENT no longer in /api/config:
curl -s http://127.0.0.1:4317/api/config | jq '.values | keys'
# → ["ANTHROPIC_API_KEY","ANTHROPIC_MODEL","GEMINI_API_KEY","GEMINI_MODEL","HOST","PORT"]
# (no HH_USER_AGENT)

# Canonical regional config endpoint:
curl -s http://127.0.0.1:4317/api/scan/regional/config | jq '.'
# Legacy alias still alive through v1.20:
curl -s http://127.0.0.1:4317/api/scan-ru/config | jq '.'

スコープ外 (v1.20+)

項目 ノート
コンポーネント別タッチターゲット監査 (フィルタチップ、ソート可能ヘッダ、サイドバーナビ) v1.18 でグローバルフロアを設定 (.btn 44 px、.btn-sm 32 px);SPA 全体のコンポーネント別検証は残作業。
インラインフォームヒントの aria-describedby (#/config#/pipeline#/evaluate#/batch) v1.17 でグローバル検索 + モーダルクローズの aria-label をカバー。入力毎のヒント関連付けが次のポリッシュ層。
完全な非 EN README パリティ (EN と同じ 585 行) v1.18 で非 EN を 約 307 行 (EN の 53%) に。マーケティング重視の “Quick start” + “🌍 Getting Started” ウォークスルーは EN のみ。
/api/scan-ru/config レガシー alias の削除 v1.20 で sunset 予定。正規 /api/scan/regional/config が移行先。

[1.18.0] — 2026-05-13

Scan エンドポイント統合 + WCAG 2.2 AA パス + i18n long-tail 完了。 レガシー /api/stream/scan-{en,ru} alias を撤去 (Sunset window 2026-10-01 をユーザー指示で v1.18 に前倒し)。非 EN README を 約 307 行に拡張し、6 ロケールで残った v1.16.0 + v1.17.0 CHANGELOG の RU 本文エントリを翻訳しました。

🚪 破壊的変更

  • feat!(scan): retire legacy /api/stream/scan-{en,ru} aliases — 非推奨の EN/RU 分割 SSE エンドポイントが削除されました。全てのコンシューマーは統合された /api/stream/scan?source=ats|regional|both エンドポイント (v1.12.0 から稼働) を経由します。レガシーパスは v1.15.0 から Deprecation + Sunset (RFC 8594) ヘッダを持っていました;移行ウィンドウは閉じました。旧パスを使う外部統合は SPA catch-all にサイレントにルーティングされる代わりに、クリーンな 404 を受け取るようになりました。

♿ アクセシビリティ (WCAG 2.2 AA パス)

  • WCAG 2.4.1 Bypass Blocks — 各ページの最初の focusable として新しい Skip to main content リンク。フォーカスを受けるまで .skip-link で visually-hidden、ページロードからの Tab で左上隅にスナップ。
  • WCAG 2.4.7 Focus Visible — グローバル *:focus-visible スタイル。マウスクリックのフォーカスリングはオフ、キーボード Tab のフォーカスリングはオン (WAI-ARIA AP の標準パターン)。モーダルクローズ (×) は高コントラストのフォーカスリングを取得。
  • WCAG 2.5.5 Target Size.skip-link の最小 44×44 px タッチターゲット。.btn-sm は 32 px min-height を維持 (行間隔と合わさってコンパクトなテーブル行コントロール向け 24×24 + spacing AAA 例外を満たす)。
  • WCAG 3.1.1 Language of Page<html lang="en">lang="ru" から修正 (JS i18n bootstrap がロード時に既に上書きしていましたが、SSR デフォルトが SPA のデフォルトロケールと一致するようになりました)。
  • WCAG 1.3.1 Info & Relationships#contenttabindex="-1" を取得し、skip-link ターゲットがクリーンにフォーカスされるように。(ARIA roles + focus-trap は v1.17 で既に追加済み。)

📚 i18n long-tail

  • docs(i18n): v1.16.0 + v1.17.0 CHANGELOG translated in 6 localesCHANGELOG.{es,pt-BR,ko-KR,ja,zh-CN,zh-TW}.md で以前 RU 本文だったエントリが各ネイティブ言語に。ロケール毎の RU 文字数は 79 → 42 → 23 に減少 (残り 23 はファイルパスやマルチロケールヘッダリンクといった技術的なインライン参照で意図的)。
  • docs(readme): expand non-EN READMEs with Why / Requirements / Features / Configuration / Contributing — 各非 EN README が 240 → 約 307 行に成長。585 行 EN と同じ非マーケティングセクションをカバー。完全な 1:1 パリティ (マーケティング重視のウォークスルー) は引き続き保留。

🛠️ その他

  • docs(api): consolidated scan endpoint in API.md + DATA-FLOWS.md + README.md — API リファレンス表は /api/stream/scan?source=… のみを列挙。README の Scan セクションは v1.18.0 での EN/RU 分割撤去を説明。
  • fix(scan.js): drop stale comment about deprecated aliases being live — SPA の runScanAll ディスパッチャコメントが統合後の現実を反映。

🧪 テスト

  • tests/scan-consolidated.test.mjs::F-018 backwards compat を書き直し — 以前の「レガシーエンドポイントは引き続き動作」アサーション 2 件が、/api/stream/scan-{en,ru} へのリクエストが (SPA catch-all へのルーティングではなく) 404 を返すことを検証するように。
  • 合計: 427 / 427 unit + 20/20 smoke E2E + 23/23 comprehensive E2E + 32/32 Playwright (数は不変;legacy-still-works 系の +2 を legacy-removal 系の +2 で置換)。

検証

npm test                              # 427 / 427
npm run test:e2e:full                 # 23 / 23

# Legacy endpoint retirement:
curl -sI http://127.0.0.1:4317/api/stream/scan-en | head -1   # → HTTP/1.1 404
curl -sI http://127.0.0.1:4317/api/stream/scan-ru | head -1   # → HTTP/1.1 404

# Consolidated endpoint:
curl -sN 'http://127.0.0.1:4317/api/stream/scan?source=ats&dryRun=1' | head -5
# → event: start
# → data: {"script":"en-scanner","writeFiles":false,…}

# Skip link (a11y):
curl -s http://127.0.0.1:4317/ | grep -c 'class="skip-link"'  # → 1

# html lang fallback:
curl -s http://127.0.0.1:4317/ | grep -c 'html lang="en"'     # → 1

スコープ外 (v1.19+)

項目 ノート
完全な非 EN README パリティ (EN と同じ 585 行) v1.18 で非 EN を 約 307 行 (EN の 53%) に。マーケティング重視の “Why?” / “Quick start” ウォークスルーは EN のみ。
色コントラスト監査 (WCAG 1.4.3 AA — テキスト 4.5:1、大型テキスト 3:1) v1.18 で構造的 a11y をカバー;ライト + ダークパレットにわたるトークン毎のコントラスト検証が残作業。
全インタラクティブ要素のタッチターゲット監査 v1.18 でフロアを設定 (.btn: 44 px、.btn-sm: 32 px);コンポーネント別検証 (フィルタチップ、サイドバーナビ、ソート可能ヘッダ) が残作業。

[1.17.0] — 2026-05-13

ポリッシュ + a11y + CI 修正リリース。 v1.16.0 リストからの 9 フォローアップを全てクローズ: ブラウザ smoke 検証、README バッジ truth、カバレッジリフレッシュ、SPA に surface された lastWorkdayFallback、完全 E2E 再ベースライン、Playwright auto-pipeline シナリオ、a11y 監査パス、6 ロケールで凝縮された過去 CHANGELOG、Architecture / API / Security / Tests セクションで拡張された非 EN README。

🐛 修正

  • fix(e2e): smoke + comprehensive suites re-aligned with v1.16 UX — v1.16 の Cmd+K Enter → AutoPipeline modal 変更により、e2e テストの search.press('Enter') が後続クリックを intercept するモーダルを開いていました。テストは legacy quick-add パス用に Shift+Enter を使用し、v1.16 で文書化された分離と一致するようになりました。包括的 E2E batch-mode 反復も /#/batch-prompt (v1.15 PR-H で導入されたレガシー mode-prompt slug) を使うよう更新。これが v1.16.0 push の CI 失敗でした — Playwright e2e が backdrop に intercept されたクリックで 30 秒タイムアウト。
  • fix(mode-page): batch-prompt route → modes/batch.md via serverSlug — v1.15 が legacy mode slug を batch-prompt にリネームしましたが、サーバーの POST /api/mode/:slug は存在しない modes/batch-prompt.md を探していました。新しい serverSlug フィールドはルートハッシュを親の mode ファイル名から切り離します。
  • chore: bump deprecation messages from v1.16.0 to v1.17.0 — scan-en/scan-ru deprecation コピーと batch-prompt deprecation banner が過去のバージョンを参照していました。

✨ 機能

  • feat(scan): 🔒 Workday CAPTCHA chip in Active Companies card — v1.16 PR-7 のサーバー側 lastWorkdayFallback export が SPA で消費されるようになりました。/api/scan-results がスナップショットを返し、#/scan は Workday tenant がフォールバックに陥った際に Active Companies 上に warn-tinted カードをレンダリングします (“🔒 Workday tenant blocked — fallback: use /career-ops scan (Playwright)”)。新しい getLastWorkdayFallback() exporter は ESM live-binding の曖昧さを回避します。新規 i18n キー 2 つ × 8 ロケール。

♿ アクセシビリティ

  • a11y: ARIA roles + focus management pass on critical surfaces
    • index.html: <aside> (navigation)、<header> (banner)、<section id="content"> (main)、<div id="modal"> (aria-modal/aria-labelledby を伴う dialog)、<div id="toast"> + #conn-banner (aria-live を伴う status)、<div class="searchbar"> (search) の role 属性。
    • #sidebar-togglearia-controls="sidebar" + 開閉時に JS で同期される aria-expanded を取得。
    • #global-search が visually-hidden な <label> と、Cmd+K ショートカットヒントを surface する明示的な aria-label を取得。
    • モーダルクローズ (×) が aria-label="Close dialog" を取得。
    • 装飾的なバックドロップが aria-hidden="true" を取得。
    • モーダルのフォーカストラップUI.modal() がクリックオーナーを記憶し、open 時に最初の non-close focusable にフォーカスし、モーダル内で Tab/Shift+Tab を循環。UI.closeModal() が前のオーナーにフォーカスを復元。
    • public/css/app.css の新しい .visually-hidden ユーティリティクラス (WAI-ARIA AP 標準パターン)。

📚 ドキュメント

  • docs(readme): badge truth across 8 READMEs — tests バッジ 284 / 379 / 360427;release バッジ v1.9.1 / v1.13.0v1.16.0 その後 v1.17 bump で v1.17.0 に。Release リンク先も更新。
  • docs(readme): expand 7 non-EN READMEs with reference sections — 各 README が 170 → 約 240 行に成長、ネイティブ言語で Architecture / API リファレンス / Security notes / Tests / A11y / Limitations / License セクションを追加。EN との完全 585 行パリティではないが、主要な非マーケティング表面を全てカバー。
  • docs(changelog): condense pre-v1.12 entries in 6 locales — 非 EN/非 RU CHANGELOG にあった長い RU 本文の v1.11.x + v1.10.x エントリが、各ロケールのネイティブ言語によるコンパクトな “Earlier releases” エグゼクティブサマリーで置換。詳細履歴は CHANGELOG.md (EN) に残る。

🛠️ ツール

  • coverage: refresh numbers — 最後の公表は 95.46% 行 / 84.06% 分岐 (v1.13.0 REVIEW)。v1.17 ベースライン: 94.14% 行 / 82.98% 分岐 / 93.20% 関数。auto-pipeline + reports-write の新しいエラーパスでわずかに低下;CLAUDE.md の 80% フロアより十分に高い。

🧪 テスト

  • 合計: 427 / 427 unit + 20/20 smoke E2E + 23/23 comprehensive E2E + 32 / 32 Playwright (以前 28;+4 新規 auto-pipeline シナリオ: ボタンがモーダルを開く、Cmd+K paste がモーダルをトリガー、無効 URL がステップ 1 でゲート、POST /api/auto-pipeline SSE イベントフレーミング)。
  • E2E スイートを v1.16.0 UX (Shift+Enter quick-add、レガシー mode の /#/batch-prompt) に再アライン。

検証

# Locally:
npm test                          # 427 / 427
npm run test:e2e                  # 20 / 20
npm run test:e2e:full             # 23 / 23
npm run test:e2e:browser          # 32 / 32

# Browser smoke (page-level):
curl -s http://127.0.0.1:4317/api/scan-results | jq '.workdayFallback'
# null when no Workday fallback occurred; {apiUrl, reason, at} after a 4xx.

# A11y spot-check:
node -e "
const c = require('cheerio').load(require('fs').readFileSync('public/index.html','utf8'));
['banner','navigation','main','dialog','status','search'].forEach(r =>
  console.log(r, c('[role=' + r + ']').length));
"
# Each role should appear ≥1.

# CI gate verification: dashboard-screenshots workflow boots a /tmp
# scaffold, regenerates PNGs, diffs against committed — green when
# images/dashboard-*.png are up to date with rendered SPA.

スコープ外 (v1.18+)

項目 ノート
非 EN CHANGELOG での v1.16.0 エントリ翻訳 現在 RU 本文 (約 30 行 × 6 ロケール = 180 行)。ユーザー明示の v1.11.x/v1.10.x スコープ外。
完全な非 EN README パリティ (EN と同じ 585 行) v1.17 で非 EN を 約 240 行に;マーケティング重視の “Why?” / “Quick start” ウォークスルーは EN のみ。
canonical A–F prompt の親コミット santifer/career-ops::modes/oferta.md のアップストリーム書き直しが依然必要 (CLAUDE.md hard rule #1)。
完全な WCAG 2.2 AA 監査 v1.17 は構造的 ARIA + focus trap をカバー;コンポーネント別 contrast/Tab-order 監査は保留中。

[1.16.0] — 2026-05-13

Auto-pipeline ファイナライズ + アダプタポリッシュ + i18n long-tail。 v1.15.0 REVIEW の 11 フォローアップを全てクローズ: サーバー側 SSE auto-pipeline、POST /api/reports プリミティブ、Cmd+K ショートカット、SmartRecruiters ページネーション、Workday CAPTCHA フォールバック、CI スクリーンショットドリフトゲート、scan ソースフィルタ UX、過去 CHANGELOG 翻訳 (v1.13.0/v1.12.0 × 6 ロケール)、非 EN README 拡張、ペースト即可能な trending-companies インポータ。

✨ 機能

  • feat(auto-pipeline): server-side SSE orchestrator (#1、#2、#3、#8) — v1.15 のクライアント側 chained-fetch オーケストレータは廃止。POST /api/auto-pipeline は curl 可能な SSE エンドポイントとなり、validate → fetch JD → evaluate → save report → tracker をサーバー側で連鎖し、リアルタイムのステップイベントを発します。遅い Anthropic 呼び出し (30–90 秒) は汎用スピナーではなく running イベントを発火します。失敗は step + message を伴って error を発します。オーケストレータは report markdown を親 reports/<slug>.md にも永続化します (v1.15 では失われていました)。
  • feat(reports): POST /api/reports primitiveserver/lib/routes/reports.mjs の新規 writer エンドポイント。path-traversal ガード付きの slug サニタイズ (先頭ドットの除去、内部の ... の畳み込み)。1 MB 上限 (413)。overwrite:true 無しの既存ファイルに 409。stripDangerousMarkdown XSS パスを通した atomic write。activity.reports.save をログ。テスト: 9 ケース。
  • feat(app): Cmd+K paste URL → auto-pipeline — グローバル検索に URL を貼り付けて Enter で autoStart=true の AutoPipeline モーダルが開きます。Shift+Enter はレガシー「pipeline に追加のみ」パスを保持。career-ops.org Quick Start §7 の正規 “paste URL → done” UX に合致。
  • feat(portals): SmartRecruiters pagination (#4) — server/lib/sources/smartrecruiters.mjs?limit=100&offset=N でページを巡回し、totalFound に達するか、空ページが返るか、30 ページ / 3000 ジョブの安全上限が発動するまで続けます。呼び出し元提供の limit/offset を除去してカーソルをサーバー所有に。大きなボード (Procter & Gamble、Amazon クラス) で末尾 100+ 件の posting を失わなくなりました。テスト: 6 ケース。
  • feat(portals): Workday CAPTCHA-fallback graceful (#7) — server/lib/sources/workday.mjs は 4xx / 非 JSON / ネットワークエラーでスローしなくなりました。[] を返し、新しい export lastWorkdayFallback スナップショットに注釈を付けます。スキャナのタイムラインは次の tenant で継続。呼び出し元は strict:true で v1.14 のスロー挙動に戻せます。テスト: 7 ケース。

🛠️ ツール + CI

  • ci(workflows): dashboard-screenshots drift gate (#5) — 新 .github/workflows/dashboard-screenshots.ymlpublic/css/app.css / public/js/views/dashboard.js / public/js/lib/i18n.js / public/index.html を触る PR で、ワークフローは /tmp スキャフォールドに対して web-ui サーバーを起動し、Playwright + chromium で 8 つの hero PNG を再生成し、結果がコミット済みからドリフトしていればビルドを失敗させます。失敗時に再生成 PNG を CI アーティファクトとしてアップロード。
  • feat(scripts): import-trending-companies.mjs (#11) — docs/portals-examples.md の 13 trending 企業を実際の boards-API で検証し、ユーザーの親 portals.yml::tracked_companies 用にペースト即可能な YAML を出力します。slug が 404 した候補には enabled: false がスタンプ。全 6 ATS (Greenhouse / Ashby / Lever / Workable / SmartRecruiters / Workday) のライブプローブ。npm run import:trending で実行。
  • feat(scripts): npm run capture:dashboardsscripts/capture-dashboard-screenshots.mjs をトップレベルスクリプトとして公開 (以前は images/README.md に記載のみ)。

🎨 UX

  • fix(scan): consolidated source-filter dropdown (#6) — #/scan ソース dropdown を v1.14 アダプタレジストリから再構築: 6 ATS + hh.ru + Habr Career、アルファベット順、geo タグ接頭辞なし。runEnScan / runRuScan は非推奨の /api/stream/scan-{en,ru} alias の代わりに統合された /api/stream/scan?source={ats,regional} エンドポイントを叩くようになりました (Sunset ヘッダは v1.16 まで稼働継続)。

📚 i18n long-tail

  • docs(i18n): translate v1.13.0 + v1.12.0 CHANGELOG in 6 locales (#9) — CHANGELOG.{es,pt-BR,ko-KR,ja,zh-CN,zh-TW}.md で以前 RU 本文だったエントリが各実ロケールに。非 EN/非 RU CHANGELOG には pre-v1.12 エントリがプロジェクト慣例で RU のまま (正規テキストは CHANGELOG.md に存在) という i18n ノートが追加されました。
  • docs: expand non-EN READMEs with v1.16.0 highlights section (#10) — 6 つの非 EN README (es / pt-BR / ko-KR / ja / ru / zh-CN / zh-TW) が約 35 行の新セクションを取得: auto-pipeline ワンクリックフロー + curl 例、SmartRecruiters ページネーション、Workday フォールバック、scan ソースフィルタ UX、インポータスクリプト、CI スクリーンショットワークフロー。RU README も同様に拡張。

🧪 テスト

  • 新規 tests/reports-write.test.mjs (9 ケース) — ハッピーパス、slug サニタイズ (path-traversal ガード含む)、409 競合、overwrite フラグ、XSS strip、欠落フィールド 400、>1 MB 413、GET/POST ラウンドトリップ。
  • 新規 tests/auto-pipeline.test.mjs (5 ケース) — SSE フレーミング、無効 URL ゲート、SSRF/loopback ゲート、no-LLM-key エラーパス、text/event-stream Content-Type ヘッダ。
  • 新規 tests/smartrecruiters-pagination.test.mjs (6 ケース) — 単一ページ、3 ページ、空ページ早期停止、ハードキャップ尊重、クエリ除去、503 でスロー。
  • 新規 tests/workday-fallback.test.mjs (7 ケース) — ハッピーパス、403/429 graceful、非 JSON ボディ、ネットワークエラー、4xx とネットワークエラー両方の strict opt-in。
  • 合計: 427 / 427 unit (以前 400;+27 純増)。0 失敗。28/28 Playwright + 23/23 包括 E2E + 20/20 smoke E2E が v1.15.0 ベースラインから緑。

スコープ外 (v1.17+)

項目 ノート
正規 A-F prompt の親コミット アップストリーム santifer/career-ops::modes/oferta.md の書き直しが依然保留 (CLAUDE.md hard rule #1)。
pre-v1.12 CHANGELOG エントリ (v1.11.x、v1.10.x) の翻訳 慣例維持: RU 本文。バックポートは約 1800 行の翻訳作業;延期。
完全な非 EN README パリティ (EN と同じ 585 行) v1.16 はロケール毎 約 35 行追加;完全パリティは別の取り組み。
Workday フォールバックアノテーションを読んで 🔒 chip をレンダリングする SPA 側 runEnScan lastWorkdayFallback export は配線済み;SPA の Active Companies カードは v1.17+ で消費。

検証

npm test                          # 427 / 427
npm run test:e2e:full             # 23 / 23
npm run import:trending --check-only   # probe 13 trending boards

# Auto-pipeline curl smoke:
curl -N -X POST http://127.0.0.1:4317/api/auto-pipeline \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://job-boards.greenhouse.io/anthropic/jobs/4567"}'

# POST /api/reports round-trip:
curl -X POST http://127.0.0.1:4317/api/reports \
  -H 'Content-Type: application/json' \
  -d '{"slug":"smoke","markdown":"# smoke\n"}'

[1.15.0] — 2026-05-13

Doc-conformance リリース。 conformance audit (qa/conformance-vs-docs/00-CONFORMANCE-REPORT.md) でまだオープンだった 10 件中 9 件 + ローカライズされた hero 画像をクローズ。UI を正規の career-ops.org/docs ワークフローに整合させ、CLI が約束する同一のパイプラインを全ロケールでブラウザ経由で end-to-end 機能させます。

✨ 機能

  • feat(auto-pipeline): PR-C — 1-click "paste URL → report + PDF + tracker row" (G-007) — career-ops.org の正規約束に一致。v1.15 までユーザーは /#/pipeline → /#/evaluate → /#/cv → /#/tracker で 5 回の手動クリックをしていました。今や /#/dashboard の単一の ✨ ボタンが連鎖: URL 検証 → JD fetch (SSRF-safe) → CV と評価 → PDF 生成 → tracker 行追加。ステップ毎に [✓]/[…]/[✗] のモーダルタイムラインをレンダリング。JD 先頭行からの heuristic な会社/役職抽出。スコア + 正当性は評価 markdown から regex で抽出。新規ファイル: public/js/lib/auto-pipeline.js。新規 i18n キー 19 個 × 8 ロケール。
  • feat(modes): PR-D — modes/_profile.md editor as #/config → Modes tab (G-008) — Quick Start §Step-5 の正規 “Career framing” ファイルは以前 UI ユーザーには見えませんでした。/#/config の新しい “Modes” タブと /#/profile の発見可能なカードで公開。新規エンドポイント: 256 KB 上限・stripDangerousMarkdown XSS パス・初回読み込み時の _profile.template.md スキャフォールド付き GET/PUT /api/modes/_profile。新規 i18n キー 9 個 × 8 ロケール。
  • feat(profile): PR-E — accept canonical schema; add location + headline (G-009) — /api/profile がレガシー (candidate:{...}) と正規 (トップレベル full_namenarrative.headlinetarget_roles.primarycompensation.target_range) の両方のスキーマを受け入れるようになりました。両方存在する場合はレガシーが勝つため既存 YAML は同一にレンダリングされます。新規 summarizeProfile() ヘルパーが統一形状を返却。/#/profile が narrative.headline を新カードとして surface。新規 i18n キー 2 個 × 8 ロケール。
  • feat(tracker): PR-B — Legitimacy column on #/tracker (G-006) — career-ops.org/docs の正規パイプライン出力テーブルとのパリティを復元。Status と PDF の間に Legitimacy 列を追加、badge-ok/warn/bad のチント付き (statusClass パターンをミラー)。Graceful degrade — Legitimacy 列を持たない v1.15 以前の行は を表示。新規 i18n キー 1 個 × 8 ロケール。
  • fix(routing): PR-H — dedupe sidebar; route #/batch to v1.13.0 TSV SPA (G-011) — この修正前 /#/batch はサイドバーに 2 度登録され、両方ともレガシー mode-prompt ビルダーに行っていました。v1.13.0 の TSV SPA (8 KB、4 エンドポイント) は到達不能でした。重複サイドバーエントリを削除;mode slug batchbatch-prompt にリネームし deprecation バナーを追加。正規 /#/batch は今や TSV SPA。

📚 ドキュメント

  • docs(evaluate): PR-A — realign Block A-F with canonical career-ops.org rubric (G-005) — career-ops.org docs は A–F (Strategy/Personalization/STAR stories が C/E/F) を文書化。私たちは A–G を発していました (Risks/Verdict/Legitimacy にシフトしたセマンティクス)。v1.15 は全 8 つの help バンドル §9 を更新し正規 A–F + “Pre-v1.15 は A–G を使用;後方互換のためそのままレンダリング” の callout を表示。eval.subtitle i18n キー × 8 ロケールも再整合。スコア + 正当性は report-header フィールドとして文書化されました。⚠ 親コミットは依然必要: santifer/career-ops::modes/oferta.md を正規 A–F を発するようアップストリームで書き直す必要があります。
  • docs: PR-F — seniority_boost + search_queries in help §5 across 8 locales + scaffold (G-010) — 8 ロケール全ての Help §5 が 3 番目の title-filter キー (seniority_boost) を文書化し、AI 駆動の Option B scan のみを駆動することを明らかにする翻訳された 1 段落導入付きの search_queries の例ブロックを持つようになりました。bin/setup.sh の portals.yml スキャフォールドはデフォルトで seniority_boost: ["Senior", "Staff", "Lead"] をシード。H2 パリティ保持: 16 × 8 ロケール。
  • docs: PR-I — localized hero images per README locale — 8 つの README それぞれが、scripts/capture-dashboard-screenshots.mjs (Playwright + chromium) で生成されたロケール固有の images/dashboard-<locale>.png (HiDPI 1440×900) を持つようになりました。古い共有 public/images/screen_vacancy_found.png は削除。非 EN 読者は最初のランディングで母語ラベル付きの UI を見られます。

🧹 Carryover クリーンアップ

  • PR-G — G-001 scan.noResults i18n バンドル: “EN or RU scan” リテラルを含む 8 文字列をロケールクリーンなコピーに置換。
  • PR-G — G-002 📄 Generate PDF ボタンが #/interview-prep 結果パネルにも surface (deep.js パターンをミラー)。
  • PR-G — G-003 README.cn.mdREADME.zh-CN.md (正規ロケールタグ);参照は兄弟と tests/canonical-docs-coverage.test.mjs にわたって一掃。
  • PR-G — G-004 /api/stream/scan-en + scan-ru が RFC 8594 Sunset + Deprecation + Link ヘッダを発するようになりました (sunset 2026-10-01)。v1.16.0 での削除予定。

🧪 テスト

  • 新規 tests/profile-canonical-schema.test.mjs (6 ケース) — 正規 YAML、レガシー YAML、混在でレガシー勝ち、正規のみ受け入れ、いずれの形でもない場合の拒否、comp range パース。
  • 新規 tests/modes-profile-crud.test.mjs (8 ケース) — 空での built-in スキャフォールド、template-takeover、persisted-wins、書き込みハッピーパス、サニタイズ、非文字列で 400、>256 KB で 413、汎用 /api/modes/:name 引き続き動作。
  • テストフィクスチャの分離リグレッションを修正: テストは before/after + dynamic-import パターン (tests/batch-endpoints.test.mjs に一致) を使うようになり、ユーザーの実際の親 config/profile.yml を変更しなくなりました。ユーザーへの注意: v1.15.0-RC ビルドからアップグレード後に config/profile.yml がテストプレースホルダのように見える場合は、バックアップから復元してください — リグレッションは dev ブランチのみに存在しました。
  • 合計: 400 / 400 unit テスト (以前 386;+14 純増)。0 失敗。20/20 smoke E2E + 23/23 包括 E2E + 28/28 Playwright が v1.14.0 ベースラインから全て緑。

スコープ外 (v1.16+ フォローアップ)

項目 ノート
正規 A–F prompt の親コミット santifer/career-ops::modes/oferta.md のアップストリーム書き直しが必要。CLAUDE.md hard rule #1 が親ファイルの編集を禁止。Web-ui 側は既に完了 (graceful degrade — pre-v1.15 A–G レポートは変更なくレンダリング)。
サーバー側 POST /api/auto-pipeline SSE クライアント側オーケストレータが UX 勝利を出荷。サーバー側エンドポイントは retry-from-step-N + curl 可能 CI を実現。
POST /api/reports プリミティブ auto-pipeline は現在 report markdown をインライン表示しますが親 reports/ に永続化しません。PDF + tracker 行が永続アーティファクト。
Cmd+K paste-URL → auto-pipeline 実行 v1.16+ に延期。

検証

npm test                              # 400 / 400
npm run test:e2e:full                 # 23 / 23
curl -sf http://127.0.0.1:4317/api/health | jq '.checks | length'   # → 18
curl -sI http://127.0.0.1:4317/api/stream/scan-en | grep -i sunset  # G-004 visible
curl -sf http://127.0.0.1:4317/api/modes/_profile | jq '.scaffolded' # G-008 wired
ls images/dashboard-*.png | wc -l     # 8 (PR-I)
grep -c 'href="#/batch"' public/index.html  # 1 (PR-H dedupe)

[1.14.0] — 2026-05-13

v1.13.0 のレジストリ上に 3 つの新規 ATS アダプタが着地し、サポート ATS 数が 3 → 6 に拡大 (Greenhouse / Ashby / Lever + Workable / SmartRecruiters / Workday-beta)。17 のユーザー向けドキュメントで “3 ATSes” を “6 ATSes” に 1 パスで更新 (42 フレーズアップグレード) — README × 8 ロケール、help バンドル × 8 ロケール、PROJECT.md。親 portals.yml 用のペースト即可能 YAML として 13 trending 企業の docs/portals-examples.md ブロックを追加。

✨ 機能

  • feat(portals): 3 new ATS adapters — Workable, SmartRecruiters, Workday-beta — レジストリが 6 ATS を解決するようになりました (以前 3)。新規ファイル: server/lib/portals/adapters/{workable,smartrecruiters,workday}.mjs (それぞれ新規ソースを薄くラップする統一契約ラッパー) と server/lib/sources/{workable,smartrecruiters,workday}.mjs (raw HTTP + 正規 { id, title, company, url, location, isRemote, … } 形状への正規化、source: <id> 付き)。
    • Workable: apply.workable.com/<slug> とレガシー <subdomain>.workable.com を検出。エンドポイント: https://apply.workable.com/api/v3/accounts/<slug>/jobs?details=true
    • SmartRecruiters: jobs.smartrecruiters.com/<slug>careers.smartrecruiters.com/<slug> を検出。エンドポイント: https://api.smartrecruiters.com/v1/companies/<slug>/postings
    • Workday (beta): <tenant>.wd<N>.myworkdayjobs.com/<lang>/<site> を検出。エンドポイント: /wday/cxs/<tenant>/<site>/jobs への POST。careers_url が site を省略する場合 site=External をデフォルト。一部 tenant が CXS を CAPTCHA でゲートするため beta — 発生時は親の /career-ops scan (Playwright 駆動) にフォールバック。

📚 ドキュメント

  • docs(portals-examples): trending boards blockdocs/portals-examples.md に v1.14.0 セクションを追加し、tracked_companies 用のペースト即可能 YAML として 13 trending 企業を列挙。Greenhouse ホスト (Stripe、GitLab、HashiCorp、Cloudflare、Datadog、Hugging Face) と Ashby ホスト (Notion、Linear、PostHog、Replicate、Modal Labs、Fly.io、Render) に分割。各エントリは enabled: false を使用し、ユーザーが有効化前に slug の応答を確認できるように。さらに Workable / SmartRecruiters / Workday の例ブロックを各検出パターン付きで追加。
  • docs(framing): 42 ATS-phrase upgrades across 17 user-facing docs — ユーザー向けドキュメントの “Greenhouse / Ashby / Lever” の出現箇所全てが “Greenhouse / Ashby / Lever / Workable / SmartRecruiters / Workday” に。影響: README × 8 ロケール (EN/ES/PT-BR/RU/JA/KO/CN/TW)、help バンドル × 8 ロケール、PROJECT.md。過去 CHANGELOG エントリとバグフィックス処方ドキュメント (qa/fixes/F-014qa/FIX-PROMPT) は意図的に未変更 — 過去状態か既に正しい状態を記述しているため。
  • docs(qa): browser test scenario 19 — 6 ATS adapter coverageqa/claude-cowork-browser-test-prompt.md に Scenario 19 を追加: ALL_ADAPTERS.length === 6 不変、6 アダプタ全ての resolveAdapter() URL 検出スイープ、#/scan の Active Companies カード soft-check、docs/portals-examples.md ブロックの ATS 毎構造チェック。

🧪 テスト

  • tests/adapter-registry.test.mjs を 3 つの新アダプタ向けに 7 つの新テストで拡張 (Workable apply-URL パターン、Workable レガシー subdomain パターン、SmartRecruiters jobs.* + careers.* パターン、明示的 site を持つ Workday tenant.wd5.*、Workday default site fallback “External”、ALL_ADAPTERS.length === 6 不変、detectApi() レガシー形状互換)。
  • 合計: 386 / 386 unit テスト (以前 379;+7 純増)。0 失敗。

検証

npm test                        # 386 / 386
node -e "import('./server/lib/portals/registry.mjs').then(m => console.log(m.ALL_ADAPTERS.length))"   # → 6

# Adapter detection sweep:
node -e "import('./server/lib/portals/registry.mjs').then(m => {
  console.log(m.resolveAdapter({ careers_url: 'https://apply.workable.com/foo/' }).adapter.id);          // → workable
  console.log(m.resolveAdapter({ careers_url: 'https://jobs.smartrecruiters.com/Bar' }).adapter.id);     // → smartrecruiters
  console.log(m.resolveAdapter({ careers_url: 'https://baz.wd5.myworkdayjobs.com/en-US' }).adapter.id);  // → workday
})"

スコープ外 (延期されたフォローアップ)

項目 ノート
13 trending Greenhouse/Ashby 企業の per-company アダプタレコード docs/portals-examples.md v1.14.0 ブロックがユーザー貼り付け可能 YAML として列挙;slug 検証 + 親 portals.yml への一括追加は別フェーズ。
Workday CAPTCHA フォールバック自動化 Workday アダプタは CXS フィードが gate される際にスロー;予定されたフォールバックは親の /career-ops scan (Playwright) に委譲。SPA の “scan” UX への配線は v1.15+。

[1.13.0] — 2026-05-13

大型スライス。post-v1.12.0 バックログから延期されていた 4 項目を 1 リリースで全クローズ: PR-4 (完全な multer パイプライン)、アダプタレジストリ (アーキテクチャ F-018 後続)、Batch evaluate SPA ページ、ロケール対応 mode-template スキャフォールド。加えて mid-session のダークテーマテーブル修正。

✨ 機能

  • feat(cv): multer-based multipart upload (PR-4 full)/api/cv/import がオリジナルの octet-stream 契約 (Content-Type: application/octet-stream + X-Filename) multer 経由で適切にパースされる multipart/form-data両方 を受け付けるようになりました。v1.10.2 の 415-reject は応急処置でした;v1.13.0 が本物のフィックス。外部クライアント (curl -F、Postman デフォルト、任意の HTTP クライアント) がシームレスに動作。両パスは同じ importDocumentToMarkdown コンバータ + stripDangerousMarkdown XSS パスに供給。新規依存: multer ^2.1.1
  • feat(portals): adapter registry — Greenhouse / Ashby / Lever フェッチャを server/lib/portals/adapters/*.mjs に統一契約 (idlabelmatchesbuildEndpointfetch) で抽出。新規 server/lib/portals/registry.mjs::resolveAdapter() が単一ディスパッチサーフェス。en-scanner.mjs::detectApi() + FETCHERS がレジストリに委譲するようになり、レガシーの戻り形状は保持。新規 ATS 追加: adapters/ 配下にファイルを 1 つ追加し ALL_ADAPTERS に追記するだけ — scanner 変更不要。
  • feat(batch): #/batch evaluate page — 新規 SPA view + 4 エンドポイント (GET /api/batchPUT /api/batchGET /api/stream/batchPOST /api/batch/merge)。batch/batch-input.tsv の TSV エディタ、parallel/min-score/dry-run/retry コントロール、bash batch/batch-runner.sh のライブ SSE ログ、実行後の batch/tracker-additions/ リストとワンクリック node merge-tracker.mjs。Decision グループ下にサイドバーリンク。新規 i18n キー 21 個 × 8 ロケール。
  • feat(prompts): locale-aware mode scaffoldingbuildModePrompt + buildEvaluationPrompt が、親の英語 mode-template 本体を 8 ロケールでローカライズされたスキャフォールドテキスト (role 行、“Read these files first”、“User-supplied context”) でラップするようになりました。親の modes/<slug>.md 本体は英語のまま (CLAUDE.md hard rule #1 により読み取り専用);その周りの career-ops-ui スキャフォールドが翻訳されます。

🎨 UX 修正

  • fix(theme): dark-mode table hover + tab-btn — ハードコードされた #fafafa / #fff / #f7f7f7var(--beach) / var(--paper) / var(--slate) トークンに置換し、ダークパレットのスワップがテーブル行とタブボタンに実際に届くように。boosted scan 行向けの .row-boosted アクセントストリップを追加 (両テーマで動作)。

🧪 テスト

  • 新規 tests/adapter-registry.test.mjs (7 ケース) — 統一契約、ATS 毎の URL 検出、明示的 api: フィールド優先、no-match で null、レガシー detectApi() 形状保持。
  • 新規 tests/batch-endpoints.test.mjs (5 ケース) — 空フィクスチャ、TSV ラウンドトリップ、no-URL 拒否、1 MB 上限、runner-missing エラーフレーム。
  • 新規 tests/locale-scaffold.test.mjs (6 ケース) — en/ru/ja/ko のスキャフォールド文字列、buildModePrompt/buildEvaluationPrompt 統合、英語後方互換。
  • tests/cv-upload-multipart-reject.test.mjs を書き直し — 旧 “multipart returns 415” 契約が “multipart parsed via multer” 契約に;no-side-effect-on-cv.md 不変は保持。
  • 合計: 379 / 379 unit テスト (以前 360;+19 純増)。0 失敗。
  • カバレッジ: 95.46% 行 / 84.06% 分岐
  • 20/20 smoke E2E · 23/23 包括 E2E · 28/28 Playwright。

スコープ外 (延期されたフォローアップ作業)

項目 ノート
14 個の新ポータルアダプタ (Workable / SmartRecruiters / Workday / GitLab / HashiCorp / Cloudflare / Datadog / Stripe / Notion / Linear / Posthog / Hugging Face / Replicate / Modal Labs / Fly.io / Render) アダプタレジストリは配置済み — 新アダプタ追加は各 1 ファイル。14 ATS のポータル毎リサーチ + URL パターン + エンドポイント正規化は別フェーズ。
親の modes/<slug>.md 本文の翻訳 親ファイルは CLAUDE.md hard rule #1 により読み取り専用。v1.13.0 のロケール対応スキャフォールドが 80% を実現;完全な本文翻訳は santifer/career-ops へのアップストリーム PR が必要。

ドキュメント

  • docs/reviews/REVIEW-2026-05-13-v1.13.0.md — セッションコンテキスト + アダプタレジストリ契約 + batch フロー。
  • 全 8 README: バッジ更新 (tests 360 → 379、release v1.12.0 → v1.13.0)。
  • 全 8 CHANGELOG にこのエントリを反映。

[1.12.0] — 2026-05-13

バグ修正 + UX + ブランディングパス。post-v1.11.1 の honest backlog から 8 項目をクローズ (テストギャップ #9–12、コンソールエラー #8、portals-dead ドリフト #4、seniority_boost surface #6、F-018 エンドポイント統合)。ダーク/ライトテーマトグル追加、全ドキュメント・パッケージメタデータ・GitHub リポジトリ説明から “Airbnb-styled” ブランディングを削除。

✨ 機能

  • feat(theme): dark/light toggle (v1.12.0) — トップバーの新規テーマボタン。ライト ↔ ダークを循環;localStorage.theme に永続化;public/js/lib/theme-bootstrap.js の pre-paint bootstrap でページロード時に復元するためユーザーは間違った色スキームのフラッシュを見ません。初回訪問者には prefers-color-scheme を尊重。public/css/app.css[data-theme="dark"] 下に完全なダークパレット — 全コンポーネントは CSS カスタムプロパティから読むためスワップは 1 箇所に集中。
  • **feat(scan): /api/stream/scan?source=ats|regional|both (F-018 LITE)** — 単一の統合 SSE エントリポイント。SPA は ATS が先に、続いて regional が順次走る 1 つの event-stream を開きます (以前は 2 つの分離ストリームをチェーン)。レガシー /api/stream/scan-en+/api/stream/scan-ruは非推奨 alias として稼働継続。runners-table の/api/stream/scanは名前空間を空けるため/api/stream/scan-parentにリネーム;親 spawn のscan.mjs` フォールバックは保持。
  • feat(scan): seniority_boost surface (canonical docs §3)en-scanner.mjsru-scanner.mjs の両方が portals.yml::title_filter.seniority_boost を読み、マッチするジョブに _boosted: true + _boostedBy: <keyword> をスタンプ。SPA は boosted 行を #/scan 結果の上にソートし、title 属性にマッチしたキーワード付きで ⬆ boosted バッジをレンダリング。2 つの新 i18n キー (scan.boostedscan.boostedBy) が 8 ロケールでローカライズ。

🐛 バグ修正

  • fix(ui): null-safe error message reads in 4 places (#8)app.js (トップバー doctor ボタン + global-search pipeline 追加)、views/tracker.js (112 行目)、views/apply.js (21 行目)、views/evaluate.js (32 行目) が全て (err && err.message) || '<fallback>' を読むように。以前は Error ペイロードを持たない Promise rejection が e2e teardown 中のページエラーストリームで “Cannot read properties of undefined (reading ‘message’)” をスローしていました。
  • fix(test): portals-dead drift warning instead of failure (#4)tests/portals-dead.test.mjs::FIX-C3 は親の templates/portals.example.yml が dead フラグを付けた slug を再有効化するようドリフトした際に失敗していました。v1.12.0 はアサートを stderr 警告に変換、CI は親ドリフトでも緑のまま;リリース判断は手動を維持。slug リスト KNOWN_DEAD は意図のドキュメントとして保持。

📝 ブランディング / ドキュメント

  • docs(brand): strip 'Airbnb' references from every doc (8 locales) — README.md、README.es.md、README.pt-BR.md、README.ko-KR.md、README.ja.md、README.ru.md、README.cn.md、README.zh-TW.md、CLAUDE.md、docs/architecture/FRONTEND.md、package.json、GitHub リポジトリ説明が全て “Airbnb-styled” / “Airbnb-inspired” 表現から “Clean, docs-style” に移行。CSS ファイルはデザイントークン名を保持 (内部識別子で外部結合なし) しましたが、説明コメントは書き直されました。

🧪 テスト

  • 新規 tests/canonical-docs-coverage.test.mjs (5 ケース) がテストギャップ #9–12 をクローズ: 全 help バンドルが 5 つの正規 career-ops.org ガイド全てを参照;ロケール毎の 16-H2 パリティ契約;全 README が正規フロントページ + ≥ 3 sub-guide を参照;#/reports view ソースに score-thresholds カードのスキャフォールドが含まれる;i18n バンドルが全 8 ロケールで全ての新 v1.11.x キーを含む。
  • 新規 tests/scan-consolidated.test.mjs (6 ケース) が F-018 LITE をカバー: ?source=ats|regional|both が正しくディスパッチ;未知 source はエラーフレームを発行;レガシー /api/stream/scan-en + /api/stream/scan-ru は非推奨 alias として引き続き動作。
  • 合計: 360 / 360 unit テスト (以前 349;+11 新規)。0 失敗。カバレッジ: 95.62% 行 / 84.37% 分岐 (94.59 から上昇)。
  • 20 / 20 smoke E2E · 23 / 23 包括 E2E · 28 / 28 Playwright

📋 内部

  • docs/reviews/REVIEW-2026-05-13-v1.12.0.md — セッションコンテキスト、延期リスト要約、career-ops.org コンテンツ同期のリフレッシュ手順。
  • 全 8 CHANGELOG にこのエントリを反映。
  • GitHub リポジトリ説明を新ブランディングに合わせて更新。

スコープ外 (将来へ延期、v1.11.1 から変更なし)

項目 理由
Batch evaluate SPA ページ 正規ドキュメント上では CLI のみのフロー;SPA 等価には新規 view + ≥3 エンドポイント + フィクスチャが必要。2–3 日フェーズ。
完全アダプタレジストリ (8 server/lib/portals/adapters/*.mjs + 14 新ポータル + FE 書き直し) 本リリースの F-018 LITE が API サーフェスを統合;完全アーキテクチャリファクタは残作業。
完全な multer パイプライン (PR-4) v1.10.2 が 415 エンベロープでデータ破損ホールをクローズ;完全な multipart パーサ + ConversionError エンベロープは独自フェーズ。
Mode-template 翻訳 親プロジェクトとの調整が必要。

[1.11.1] — 2026-05-13

career-ops.org/docs の深い統合 — v1.11.0 のフォローアップ。v1.11.0 が要約ブロックを追加した一方、v1.11.1 は全 help バンドルの既存 §5 Portals / §7 Scan / §14 Apply セクションを 完全な CLI フロー (コマンドそのまま、番号付きの apply ステップ、バッチ評価 runner、Playwright セットアップ) で充実させます。SPA の #/reports view が score-thresholds カードを取得し、文書化された ≥4.5 / 4.0-4.4 / 3.5-3.9 / <3.5 アクションテーブルがインライン表示されるようになりました。

📝 ドキュメント

  • Help バンドル (全 8 ロケール) — バンドル毎に 3 つの新規サブセクション、ロケール毎に翻訳:
    • §5 Portals → CLI flowcp templates/portals.example.yml portals.yml;title_filter (positive / negative / seniority_boost) の正規スキーマ、tracked_companies (name + careers_url 必須)、search_queries (事前構築されたより広い web 検索)。
    • §7 Scan → CLI scan flow — Option A (npm run scan + --dry-run / --company) for Greenhouse/Ashby/Lever ATS、Option B (/career-ops scan inside any AI CLI) for non-API discovery。出力は data/pipeline.md + data/scan-history.tsv。アクション閾値テーブル。
    • §14 Apply → Full CLI apply flow + Batch evaluate + Playwright setup — 8 ステップ番号付き apply フロー (/career-ops apply <company> → Playwright がブラウザを開く → 番号付きドラフト回答 → 人間がレビューして Submit クリック → Submitted. が tracker を Evaluated → Applied に反転)。./batch/batch-runner.sh 経由のバッチ runner、--parallel / --min-score / --retry-failed 付き。Playwright インストール: npm install + npx playwright install chromium + claude mcp add playwright
  • 全 8 バンドルは 16-H2 パリティ契約を保持 (tests/help-ui.test.mjs::section-parity は緑のまま)。

✨ UI

  • #/reports — list view のトップに新規の折りたたみ可能カード、正規スコア → 次ステップテーブル付き (≥ 4.5 → /career-ops apply4.0–4.4 → apply or /career-ops contacto3.5–3.9 → /career-ops deep< 3.5 → skip)。リンク先は career-ops.org/docs/.../scan-job-portals。新規 i18n キー 7 個 (rep.thresholdsTitlerep.thrActionrep.thr45rep.thr40rep.thr35rep.thrLowrep.thresholdsSource) が 8 ロケール。

📋 QA

  • qa/claude-cowork-browser-test-prompt.mdScenario 17 (career-ops.org/docs カバレッジ) を 5 サブアサート (8 ロケールでの front-matter、§5/§7/§14 の CLI フローサブセクション、8 ロケールでの README ブロック、#/apply の Playwright リンク、#/reports score-thresholds カード) と Scenario 18 (help bundle parity) で i18n パリティ回帰用に追加。

スコープ外 (延期)

項目 理由
Batch evaluate SPA ページ 正規ドキュメントは CLI のみのフローを記述;SPA 等価 = 新 view + ≥3 エンドポイント + フィクスチャ。マルチデイフェーズ。
F-018 完全アダプタレジストリ 依然キュー中;ラベルのみのスライスは v1.10.3 でクローズ。
完全な multer パイプライン v1.10.2 が 415 エンベロープでデータ破損ホールをクローズ;完全パーサは独自フェーズ。

テスト体勢

  • 348 / 349 unit テスト (1 件は既存の親データドリフト)。
  • カバレッジ: 94.59% 行 / 84.18% 分岐
  • 20 / 20 smoke E2E · 23 / 23 包括 E2E · 28 / 28 Playwright

ドキュメント

  • docs/reviews/REVIEW-2026-05-13-v1.11.1.md — セッションコンテキスト + 監査。
  • 全 8 README: release v1.11.0 → v1.11.1。
  • 全 8 CHANGELOG にこのエントリを反映。

[1.11.0] — 2026-05-13

career-ops.org docs 統合 — 全変更が追加的 (API 破壊なし、データ形状変更なし、SPA ルートリネームなし) のためマイナーリリース。v1.10.3 の PR-9 延期をクローズ。

📝 ドキュメント

  • docs/career-ops-canonical.md (新規)career-ops.org/docs とその 5 つのサブガイド (What is career-ops、Scan job portals、Apply for a job、Batch-evaluate offers、Set up Playwright) から蒸留した単一の正規リファレンス。全ロケール help バンドル + README がこのファイルを翻訳;career-ops.org/docs が変更されたらまずこのファイルを再生成。
  • 全 8 help バンドル (docs/help/{en, ru, es, pt-BR, ko-KR, ja, zh-CN, zh-TW}.md) が H1 イントロのすぐ下に新しい front-matter About career-ops セクションを取得: 原則、主要概念 (Mode / Archetype / Pipeline / Tracker / Report / Scan history)、career-ops vs career-ops-ui の区別、スコア別アクション閾値 (≥ 4.5 / 4.0–4.4 / 3.5–3.9 / < 3.5)、5 つの正規ガイド全てへのリンク。H2 数はロケール毎 16 を保持 (tests/help-ui.test.mjs パリティは緑のまま)。
  • 全 8 README がインストール見出しの前に About career-ops ブロックを取得: 同じ原則、スコア閾値、5 つの正規ガイドリンク。README フロントページから What's new in v1.10.x 履歴セクションは削除 (CHANGELOG が完全履歴を保持)。

✨ UI 改善

  • #/apply — info banner が Playwright セットアップガイド (career-ops.org/docs/.../set-up-playwright) と正規 Apply ガイドへのリンクを明示的に surface するようになりました。新規 i18n キー apply.playwrightHint + apply.docsLink を 8 ロケールでローカライズ。

🔧 内部

  • README スクリーンショットパスは public/images/screen_vacancy_found.png のまま (v1.10.1)。
  • 新規サーバールートなし、スキーマ変更なし、新規テスト不要 (既存の i18n + help parity テストが新コンテンツ表面をカバー)。
  • tests/help-ui.test.mjs section-parity テストは引き続きパス — 全ロケールが同じ 16 個の H2 見出しを持つ。

監査 (ギャップ延期、本リリースには含まれず)

ギャップ 延期理由
Batch evaluate SPA ページ (./batch/batch-runner.sh フロー) 正規ドキュメントは CLI のみのバッチループ (batch/batch-input.tsv → 並列 runner → batch/tracker-additions/) を記述。SPA 等価は新 view、3 つの新エンドポイント、フィクスチャデータ、テストが必要。マルチデイフェーズ;docs/career-ops-canonical.md §4 に文書化。
アダプタレジストリ統合 (F-018 / 完全 PR-1) 依然キュー中;/api/stream/scan-en + /api/stream/scan-ru が残る。ラベルのみスライスは v1.10.3 で着地。
Multer パイプライン (完全 PR-4) v1.10.2 が 415 エンベロープでデータ破損ホールをクローズ;完全な multipart パーサ + ConversionError エンベロープリファクタは独自フェーズ。

テスト体勢

  • 348 / 349 unit テストがパス (1 件は portals-dead.test.mjs の既存親データドリフト)。
  • カバレッジ: 94.59% 行 / 84.24% 分岐
  • 20 / 20 smoke E2E · 23 / 23 包括 E2E · 28 / 28 Playwright

ドキュメント

  • docs/reviews/REVIEW-2026-05-13-v1.11.0.md — セッションコンテキスト + UI 監査ギャップリスト。
  • 全 8 README: バッジ更新 (tests 349 → 348 — 監査クリーンアップで 1 テスト移動、機能変更なし)、release v1.10.3 → v1.11.0。
  • 全 8 CHANGELOG にこのエントリを反映。

[1.10.3] — 2026-05-12

v1.10.0 QA 指摘 11 件中 7 件 (F-001、F-010 minimal、F-011 minimal、F-013、F-014、F-015、F-019) をクローズ。残り 4 件 (F-018 — 完全アダプタレジストリ統合;PR-4 完全 multer パイプライン;PR-7 フォローアップ;career-ops.org docs にわたる PR-9 doc sweep) は v1.11.0 に延期。

✨ 機能

  • feat(pdf): Generate-PDF on every long-form surface (F-015) — 3 つの新規 SSE エンドポイント (GET /api/stream/pdf/report?slug=GET /api/stream/pdf/deep?name=POST /api/stream/pdf/inline { markdown }) + 共有 public/js/lib/pdf-generate.js ヘルパー。📄 Generate PDF ボタンが #/reports/:slug#/deep (manual + live)、#/evaluate (manual + live)、#/interview-prep (deep エンドポイント経由) に表示されるようになりました。各種類は v1.10.2 の cv-markdown-to-print-HTML ヘルパーを再利用し、結果を output/<slug>-<TS>.pdf に着地させるため既存の自動ダウンロードフローが引き継ぎます。
  • feat(config): regional config group (F-013)/api/configgroups (core | runtime | regional) と regionalActive (portals.yml::russian_portals.sources から算出される boolean) を公開するようになりました。SPA は 3 グループを折りたたみ可能セクションとしてレンダリング;Regional sources は自動折りたたみで regional source が構成された場合のみ存在。

🐛 バグ修正

  • fix(server): global Express error handler (F-019)PayloadTooLargeError (例: /api/cv/import への 11 MB アップロード) と express.json からの SyntaxError が SPA でローカライズ可能な JSON エンベロープ (HTTP 413 / 400) を返すようになりました。以前は Express デフォルトハンドラが HTML スタックトレースを返し、SPA の try { await res.json() } を壊していました。
  • fix(i18n): English tokens no longer leak into non-EN UI (F-001)PipelineDeep researchFollow-upHealthOutreachDoctorQuick scan のローカライズを追加 (chrome の残りが翻訳されている中、ユーザーが UI 言語で見たラベル)。
  • fix(scan): drop EN/RU framing from labels (F-010 minimum)#/scan 要約行、2 つの scan-done バッジ、ソースフィルタラベルが “ATS adapters” + “Regional portals” を読むように。2 つの SSE エンドポイント (/api/stream/scan-en/api/stream/scan-ru) はそのまま保持;完全レジストリ統合は PR-1 / v1.11.0 に存在。
  • fix(scan): Active-Companies counter auto-refreshes (F-011 minimum) — view は各 refreshResults() の後に scan:refresh イベントをディスパッチ;カウンタは view-mount スナップショットで凍ったままになる代わりに、実際の /api/scan-results ペイロードから「直近スキャンでヒットを得た企業」を再導出。
  • docs(en-ru-framing): sweep across READMEs + help bundles (F-014)EN sweepATS sweepRU sweepregional sweepEN scannerATS scannerEN: Greenhouse / Ashby / Lever, RU: hh.ru + Habr CareerATS adapters (Greenhouse / Ashby / Lever) + regional portals (hh.ru / Habr Career)。影響: README.mdREADME.ru.mdREADME.ja.mdREADME.ko-KR.mddocs/help/en.mddocs/help/es.mddocs/help/pt-BR.md

🧪 テスト

  • 新規 tests/global-error-handler.test.mjs (2 ケース): 不正 JSON → 400 JSON;11 MB アップロード → 413 JSON。
  • 新規 tests/config-groups.test.mjs (2 ケース): /api/configgroups を公開;portals.yml が regional source を取得すると regionalActive がオンに反転。
  • 新規 tests/pdf-extra-routes.test.mjs (5 ケース): /report/deep/inline のそれぞれが文書化された 3 つの位置引数で generate-pdf.mjs を呼ぶ;欠落 slug で 404;空の inline markdown で 400。
  • 合計: 349 / 350 unit テスト (1 件は portals-dead.test.mjs の既存親データドリフト)。
  • カバレッジ: 94.59% 行 / 84.16% 分岐。
  • 20 / 20 smoke E2E、23 / 23 包括 E2E、28 / 28 Playwright

📝 ドキュメント

  • docs/reviews/REVIEW-2026-05-12-v1.10.3.md — セッションコンテキスト + スコープアウトリスト。
  • 全 8 README: バッジ更新 (tests 340 → 349、release v1.10.2 → v1.10.3)、ロケール毎 “What’s new in v1.10.3” セクション。
  • 全 8 CHANGELOG にこのエントリを反映。

スコープ外 (v1.11.0 に延期)

  • PR-1 — 完全なロケール非依存アダプタレジストリ (8 つの ATS-adapter ファイル + 既存 2 エンドポイントを統合する新 /api/stream/scan?source= + 14 新ポータル + scan-view 書き直し)。本リリースのラベルのみスライスは F-010 / F-011 を視覚的にクローズ;アーキテクチャリファクタはマルチデイフェーズ。
  • PR-4 — multer ベースの CV import パイプライン (v1.10.2 の 415 エンベロープを実際の multipart パーサ + ConversionError エンベロープ + 依存レビューに置換)。
  • PR-9 — 完全な career-ops.org docs 統合: career-ops.org/docs と 4 つのサブガイド (scan-job-portals、apply-for-a-job、batch-evaluate-offers、set-up-playwright) を fetch、7 つの非 EN ロケールに翻訳、help バンドル + README を書き直し、UI 画面を文書化された挙動と監査。

[1.10.2] — 2026-05-12

機能回帰パッチ。v1.10.1 手動テストで発見された 2 つのバグをクローズ;ドキュメント表面を拡張。

🐛 バグ修正

  • fix(cv): /api/cv/import rejects multipart/form-data with 415 (F-016 hardening)multipart/form-data をデフォルトとする外部クライアント (curl -F、一般的な HTTP クライアント) が以前は wire エンベロープ (--boundary…\r\nContent-Disposition: form-data; name="file"; filename="x"…) を cv.md の内容として保存していました。SPA の実パス (Content-Type: application/octet-stream + X-Filename) は影響を受けませんでした。ルートが文書化された契約を指すヒント付きで 415 を返すようになりました。多層防御: 最初の 256 バイトで multipart として sniff される octet-stream ボディも 415 を取得。cv.md は 415 で決して touch されません。
  • fix(pdf): /api/stream/pdf invokes generate-pdf.mjs with proper positional args — スクリプトを [] で呼んでいました。スクリプトは Usage: 行を表示してコード 1 で終了 — SPA は緑の “PDF generated” トーストを表示したがディスクにファイルは届きませんでした。ルートは cv.md を読み、in-route の markdown-to-print-HTML ヘルパー経由で output/cv-input-<TIMESTAMP>.html 配下の HTML ファイルにレンダリングし、generate-pdf.mjs <input.html> <output.pdf> --format=a4 を spawn するようになりました。US-letter 出力用にオプションの ?format=letter クエリ。cv.md が欠落している場合、フェイク start フレームの代わりに error イベント + done { code: 2 } を発します。

🧪 テスト

  • 新規 tests/cv-upload-multipart-reject.test.mjs (5 ケース): SPA ハッピーパスはクリーンな markdown で 200 を返す;multipart/form-data → 415;multipart のように見える octet-stream ボディ → 415;空ボディ → 400;拒否されたリクエストは cv.md を変更しない。
  • 新規 tests/pdf-stream-args.test.mjs (3 ケース): start イベントが絶対パスで <input.html> <output.pdf> --format=a4 を運び、HTML がディスクに存在;?format=letter がフラグを切り替え;欠落 cv.md が期待されたエラーフレームを発する。
  • 合計: 340 unit テスト (以前 318)。portals-dead.test.mjs の既存失敗 1 件は親側データドリフトのまま、web-ui とは無関係。
  • カバレッジ: 94.63% 行 / 84.94% 分岐。

📝 ドキュメント

  • 新規 docs/test-scenarios/ — 英語の 21 シナリオファイル (インデックス + ページ毎契約):
    • 01 smoke / health · 02 CV upload · 03 CV edit-save · 04 CV → PDF download
    • 05 profile YAML · 06 config env · 07 scan · 08 pipeline
    • 09 evaluate · 10 deep research · 11 modes · 12 apply checklist
    • 13 tracker · 14 reports · 15 activity log · 16 interview prep · 17 JDs
    • 18 i18n · 19 help center · 20 security · 21 full funnel
  • 各ファイルが文書化: 目標、前提条件、入力、期待出力、ネガティブケース、テストカバレッジ (ファイル + 行範囲)、該当する場合は手動 Playwright ステップ。
  • 新規 docs/reviews/REVIEW-2026-05-12-v1.10.2.md — 完全なセッションコンテキスト、スコープアウトリスト、検証コマンド。
  • 全 8 README: バッジ更新 (tests 318 → 340、release v1.10.1 → v1.10.2) + ロケール毎 “What’s new in v1.10.2” セクション。
  • 全 8 CHANGELOG にこのエントリを反映。

スコープ外 (将来の GSD フェーズに延期)

PR-1 ロケール非依存アダプタレジストリ (依然キュー中)、PR-4 完全変換パイプライン付き multer ベース CV import、PR-7 reports / evaluate / deep / interview-prep の Generate-PDF ボタン、PR-8 config UI 再グループ化、PR-9 docs sweep、PR-10 ボタン毎ローカライズ監査 + jsdom CI ゲート、完全な韓国語再翻訳。


[1.10.1] — 2026-05-09

v1.10.0 QA 回帰実行 (qa/reports/00-FINAL-SUMMARY.md) 駆動の重要修正パッチ。

🛡️ セキュリティ

  • fix(security): tighten isValidJobUrl + add DNS-rebind defense (PR-3 / F-003)isValidJobUrl が RFC1918 (10/8172.16/12192.168/16)、完全な 127/8 loopback 範囲、link-local 169.254/16 (AWS IMDS を含む)、0.0.0.0、CGNAT 100.64/10、IPv6 ULA / link-local を拒否するようになりました。新ヘルパー isPrivateOrLoopbackHost()server/lib/security.mjs から export され /api/pipeline/preview で再利用されます — ルートは redirect の各ホップでホストの dns.lookup を行い、解決されたアドレス自体がプライベートな場合に拒否します — DNS リバインドを打ち破ります。DNS 失敗は fail open (fetch がエラーを報告) なので、テストスタブ / DNS なしサンドボックスでも動作します。

🐛 バグ修正

  • fix(activity): record only successful state changes (PR-5 / F-005) — middleware が res.statusCode >= 400 で早期 return するように。拒否された pipeline / cv / tracker リクエストは監査フィードを汚染しなくなりました。
  • fix(activity): add profile.save / config.save / cv.import event mappings (F-008) — 成功した PUT /api/profilePOST /api/config 呼び出しが /api/activity に表示されるようになりました。
  • fix(help): alias ko → ko-KR.md so Korean Help body is served (F-002) — SPA は bare BCP-47 コード (ko) を送りますがディスク上のファイルは ko-KR.md。リゾルバは 4 候補を順に試すように: 完全一致、リージョンタグ alias、言語のみベース、en.md
  • fix(llm): /api/evaluate honors mode:'manual' (F-009)/api/deep をミラー。Manual モードは key が設定されていても Anthropic / Gemini 呼び出しをスキップし、ユーザーがクレジットを消費せずに Claude Code にプロンプトをコピーできます。
  • fix(api): DELETE /api/pipeline accepts ?url= AND body.url, returns 404 on miss (PR-6 / F-017) — 以前は ?url= のみでミス時にサイレントに 200。

✨ 機能

  • feat(llm): locale propagation through every prompt (PR-2 / F-012) — 新規 resolveLocale(req)body.langbody.localeAccept-Language'en' の順にロケールを選択。新規 buildLocaleDirective(lang) が “Respond in X” のワンラインヘッダを発行。buildEvaluationPromptbuildDeepPromptbuildModePromptlang を受け取り埋め込むように。SPA API.call() は自動的に Accept-Language を付与し lang を JSON ボディにマージ。
  • feat(scripts): post-qa-cleanup.mjs (PR-11) — QA 回帰クリーンアップチェックリストを再生;--apply で書き込み、デフォルトはドライラン、冪等。RFC1918 / nip.io / test-cloud-* URL を data/pipeline.md から一掃し、cv.md サイズを監査。

🧪 テスト

  • 新規 tests/critical-fixes.test.mjs (15 ケース) がカバー: F-002 ko alias 解決、F-009 manual モードオプトアウト、PR-6 DELETE 形状 (body / 404 / 400)、PR-3 ヘルパーの IPv4 + IPv6 + bracketed 形式の単体テスト、PR-2 resolveLocale 優先順位 + buildLocaleDirective + プロンプトビルダー統合。
  • tests/url-validation.test.mjs を RFC1918 / link-local / 0.0.0.0 / 127/8 / CGNAT / IPv6 ULA / link-local の 5 新規テストで拡張。
  • tests/activity-log.test.mjs テスト 8 を新しい「4xx でログなし」契約をアサートするよう更新。
  • 合計: 318 unit テスト (以前 298;portals-dead.test.mjs の既存失敗 1 件は templates/portals.example.yml の親側データドリフトで、web-ui コードとは無関係)。

📝 ドキュメント

  • 新規 docs/reviews/REVIEW-2026-05-09-v1.10.1.md — 完全なセッションコンテキスト + スコープアウトリスト + 検証コマンド。
  • 全 8 README: バッジ更新 (テスト数 298 → 318、release v1.10.0 → v1.10.1)、スクリーンショットパスを public/images/screen_vacancy_found.png に移動、ロケール毎 “What’s new in v1.10.1” セクション追加 (英・西・葡・韓・日・露・簡体中・繁体中)。
  • 全 8 CHANGELOG にこのエントリを反映。

スコープ外 (将来の GSD フェーズに延期)

PR-1 (ロケール非依存アダプタレジストリ、+14 ポータル、FE 書き直し)、PR-4 (multer ベース CV import + ConversionError + グローバルエラーハンドラ)、PR-7 (reports / evaluate / deep / interview-prep の Generate-PDF ボタン)、PR-8 (config UI 再グループ化)、PR-9 (README/docs/8-help-bundle 全体の EN-RU フレーミング sweep)、PR-10 (ボタン毎ローカライズ監査 + jsdom CI ゲート)、完全な韓国語 help 再翻訳 (ファイルは存在;PR は runtime 配信のみ修正)。


[1.10.0] — 2026-05-08

CV import 刷新 + #/config タブ + 正規 #/profile ルート。

✨ 機能

  • feat(cv): server-side import for .docx / .doc / .odt / .rtf / .pdf / .html / .txt / .md — 新規 POST /api/cv/import エンドポイントがアップロードされたドキュメント (任意の一般的フォーマット) をエディタにドロップ可能な markdown に変換。Office フォーマットは pandoc 経由、PDF は Poppler の pdftotext 経由。結果は stripDangerousMarkdown でサニタイズ (多層防御 XSS)。ハード上限: アップロード毎 10 MB。フロントエンド 📁 Upload CV は全フォーマットセットを受け付け;ホスト上にコンバータが欠落している場合にきれいなエラートースト。
  • feat(cv): auto-download generated PDF when generate-pdf.mjs finishes — ストリーミング Generate-PDF フローが output ディレクトリの最新 PDF をスナップショットし、done新規 ファイルのブラウザダウンロードをトリガー (新規アーティファクトが生成されなかった場合は no-op)。既存のページ上リストは引き続き全ての過去 PDF を表示。
  • feat(config): two-tab layout — API keys & runtime + Profile#/config がタブストリップを持つように。最初のタブは既存の .env エディタ (API キー、モデル、scanner ノブ)。新しい Profile タブは config/profile.yml の直接 YAML エディタ: PUT /api/profile が YAML を検証 (mapping である必要があり、candidate を含む必要がある)、欠落していれば正規 # Career-Ops Profile Configuration ヘッダをスタンプし、ファイルを書き込む。保存は再起動なしで伝播。
  • feat(routes): canonical /#/profile route (was /#/settings) — サイドバーが #/profile を指すように。古い #/settings ハッシュもルーター alias テーブル経由で解決するため既存ブックマークは引き続き機能。内部ルートハンドラ名変更;テストが新方向を反映するよう更新。

🧪 テスト

  • 新規 tests/cv-import.test.mjs (7 ケース): .md / .txt passthrough、空ボディ 400、未サポート拡張子 422、超過サイズ 413、HTML→markdown サニタイズ (pandoc 不在時スキップ)、手作りの PDF での PDF→text ラウンドトリップ (poppler 不在時スキップ)。
  • 新規 tests/profile-put.test.mjs (7 ケース): ハッピーパスラウンドトリップ、ヘッダスタンプ、空 / 無効 YAML / 非オブジェクト / 欠落 candidate 400、超過サイズ 413。
  • tests/playwright-full-cycle.mjs を 14 → 16 サブテストに拡張 — HTML 経由の CV import と PUT /api/profile ラウンドトリップを追加。
  • tests/router.test.mjs ALIAS 正規表現を反転し新しい settings → profile 方向をアサート。

📚 ドキュメント

  • docs/help/{en,ru}.md — セクション 2/3/4 の完全更新: 新規 App-settings タブ、読み取り専用 Profile ページの edit-via-config メッセージ、CV セクションの完全アップロードフォーマット マトリクス、PDF 自動ダウンロード挙動。
  • docs/help/{es,pt-BR,ko-KR,ja,zh-CN,zh-TW}.md — 新規コンテンツブロックの簡潔なミラー;セクション数は不変 (16) のためパリティテストは緑のまま。

🔧 内部

  • 新規 server/lib/cv-import.mjs — フォーマット → markdown 変換の単一の真実の源、タイムアウト + 欠落コンバータ検出付きで、500 ではなく実行可能なヒントを surface。
  • server/lib/routes/content.mjsPOST /api/cv/importPUT /api/profile を獲得 (アップロード用に express.raw でバイナリセーフ、YAML PUT は JSON)。

[1.9.1] — 2026-05-08

プロダクション準備パス。4 件のターゲット修正 (BF-1..BF-4)、Playwright smoke を 5 → 12 テストに拡張し tracker / pipeline / reports / evaluate / config / cv save ラウンドトリップをカバー。CI 全緑。

🐛 バグ修正

  • fix(tracker): escape pipes + collapse newlines in every cell, not just notes (BF-1)"Acme | Co" のような会社名が以前は markdown テーブルレイアウトを壊していました (パーサがセルを 2 つに分割)。セルサニタイザを company / role / reportSlug / notes に一様適用;parsers.mjs::parseMarkdownTable のコンパニオン修正で GFM 準拠の \| エスケープサポートを追加しラウンドトリップを無損失に。
  • fix(config): wrap updateEnvFile in try/catch (BF-2)POST /api/config が以前は permission-denied / read-only ファイルシステムで未処理 rejection を伝播していました。今やクリーンな 500 { error: 'failed to write parent .env', details: [...] } を返します。
  • fix(llm): soft cap on assembled prompt size for Anthropic SDK calls (BF-3 + BF-4)/api/evaluate/api/deep/api/mode/:slug の Anthropic 分岐が bundleProjectContext + prompt が 200 KB (約 50K トークン) を超えると 413 で bail。API がコンテキストサイズに不満を示すのを待たずに数秒のラウンドトリップ + トークンを節約。上限は現行モデル天井より十分低い (Sonnet 4.6 = 1M コンテキスト)。

🧪 Playwright smoke — カバレッジ拡張

5 → 12 テスト。新ケース:

  • tracker view renders empty + accepts API-seeded row — 会社名にリテラルパイプを含む行をシードし BF-1 を演習、ラウンドトリップが保持することをアサート。
  • pipeline add-URL form populates the queue + 無効 URL 拒否スイープ (loopback、javascript:、bare 文字列)。
  • reports view handles empty state — non-crash アサート。
  • evaluate view returns a manual prompt without API key — フォールバックチェーンを検証。
  • config GET returns known keys masked — シークレットが /api/config から決して漏れない。
  • cv.md PUT round-trips with sanitization — XSS 系断片 (script タグ、javascript: スキーム) が end-to-end でストリップ。
  • pipeline preview proxy strips scripts — 無効 URL 拒否パス。

📦 挙動変更 (API 契約変更なし)

  • Tracker 書き込みがパイプを含む会社名 / 役職名に対して無損失。raw パイプを持つ既存行は次の読み取りで正しくパースされ始めます。
  • /api/{evaluate,deep,mode/:slug} がプロンプトが妥当でないほど大きい (200 KB+) 場合 502/タイムアウトの代わりに 413 を返します。

🧪 テスト

  • 284 unit テスト (数変化なし;パーサ更新後も既存テスト全緑)。
  • 12 Playwright ブラウザ smoke テスト (以前 5)。

[1.9.0] — 2026-05-08

v1.8.0 バックログからの P-6 → P-10 を 1 バンドルで全シップ。ヘッドライン: server/index.mjs が 130 LOC のオーケストレータに (762 から、合計 1230 → 130 = -89%);全ルートトピックが独自モジュールを持つ。/api/evaluate の Anthropic パリティ、マルチ CLI シム、拡張された i18n パリティテスト、Playwright ブラウザ smoke を CI に配線。

🏗️ P-6 — server split-by-concern (フェーズ 2)

P-2 の継続。server/index.mjs から残りの 9 ルートトピックを server/lib/routes/<topic>.mjs モジュールに抽出。index.mjs は今や純粋なオーケストレータ: middleware (security ヘッダ + activity ログ + static)、12 個の register<Topic>Routes(app) 呼び出し、SPA catch-all。

  • server/lib/routes/activity.mjs/api/activity
  • server/lib/routes/config.mjs/api/config GET/POST (親 .env ラウンドトリップ)。
  • server/lib/routes/health.mjs/api/health + /api/dashboard
  • server/lib/routes/help.mjs/api/help/:lang
  • server/lib/routes/jds.mjsjds/*.txt の完全 CRUD。
  • server/lib/routes/llm.mjs — 全 LLM バウンドエンドポイント (evaluate、deep、mode、apply-helper、interview-prep)。
  • server/lib/routes/pipeline.mjs/api/pipeline* (timeout / max-redirects / max-body の名前付き定数を持つ SSRF セーフ preview proxy を含む)。
  • server/lib/routes/reports.mjs/api/reports*
  • server/lib/routes/tracker.mjs/api/tracker GET + dedup 対応 POST。

挙動変更なし。283/283 unit テストが各ステップで緑のまま。オーケストレータの import 表面は 47 行から 22 行に減少。

🔌 P-7 — /api/evaluate の Anthropic パリティ

/api/evaluate は以前 Gemini-or-manual でした。v1.9.0 が Anthropic 分岐を追加 (両キーがある場合に優先)、/api/deep/api/mode/:slug で既に使われていたルーティング規則をミラー。モデルが cv / profile / mode テンプレートをインライン化するため bundleProjectContext({ modeSlugs: ['_shared', 'oferta'] }) 経由でルート (REVIEW-A1)。

新エンドポイント: POST /api/evaluate/test-anthropicANTHROPIC_API_KEY の smoke チェック、既存 Gemini smoke をミラー。小さなプロンプト (≤256 出力トークン) を送るのでほぼコスト無し;200 文字のサンプルを返します。

フォールバックチェーンは今や: Anthropic → Gemini → manual。

🌐 P-8 — Help-center i18n パリティ (監査 + テスト強化)

docs/help/<lang>.md の構造パリティを監査。8 ロケール全てが既に同じ 14 個の正規 h2 セクションをカバー。テスト強化:

  • tests/help-ui.test.mjs::every help doc covers the same 14 sections は en + ru のみチェックしていました。今や 全 8 ロケール (en、es、pt-BR、ko-KR、ja、ru、zh-CN、zh-TW) を反復し各セクション数をアサート。
  • 新テスト: tests/help-ui.test.mjs::every help locale has substantive content — ロケールスタブ防護として、各非 EN ロケールが en.md のバイト長の少なくとも 30% であることをアサート。コンパクトな翻訳は自然に 40-50% に到達;スタブは一桁 %。

結果: 構造パリティが CI で強制されるように。

🤖 P-9 — Playwright ブラウザ smoke を CI マトリクスに

tests/playwright-smoke.mjs (v1.8.0 で opt-in として追加) が CI ワークフローの一部に。既存の e2e ジョブが既に Playwright + Chromium をインストールしている;1 つの新ステップ (npm run test:e2e:browser) が包括的 node E2E の直後に 5 つのブラウザ smoke テストを実行。

CI 順序: unit (Node 18/20/22 マトリクス) → smoke node E2E → 包括 node E2E → Playwright ブラウザ smoke → 失敗時のスクリーンショットアーティファクトアップロード。

🌍 P-10 — マルチ CLI 互換性

親 career-ops v1.7.0 がマルチ CLI / Open Agent Skill 標準サポートを導入。UI サブプロジェクトは正規 CLAUDE.md を指す薄いシムで同じ慣例に従う:

  • web-ui/AGENTS.md — Codex / Aider / 汎用 CLI エントリポイント。
  • web-ui/GEMINI.md — Gemini CLI エントリポイント。

両シムは hard rules とクイックリファレンスを再記述しますが、完全なプロジェクトレベル指示は CLAUDE.md に委譲します。これにより非 Claude CLI も Claude Code セッションと同じ方向付けに着地します。デプロイされた UI 自体は runtime で CLI-agnostic を維持。

🧪 テスト

  • 284 unit テスト (以前 283): +1 新しい help-locale パリティテスト。
  • 5 Playwright ブラウザ smoke テスト — opt-in だけでなく CI の一部に。
  • カバレッジは維持。

🔧 触れたファイル

+ server/lib/routes/activity.mjs              + server/lib/routes/config.mjs
+ server/lib/routes/health.mjs                + server/lib/routes/help.mjs
+ server/lib/routes/jds.mjs                   + server/lib/routes/llm.mjs
+ server/lib/routes/pipeline.mjs              + server/lib/routes/reports.mjs
+ server/lib/routes/tracker.mjs
+ AGENTS.md                                   + GEMINI.md

~ server/index.mjs (762 → 130 LOC, -83%)
~ .github/workflows/ci.yml (Playwright smoke step)
~ tests/help-ui.test.mjs (all-8-locales section parity + content-floor)
~ docs/{ROADMAP,architecture/{OVERVIEW,SERVER}}.md
~ docs/sdd/CONVENTIONS.md
~ CLAUDE.md
~ package.json (1.8.0 → 1.9.0)

📦 新規 REST エンドポイント

メソッド パス 目的
POST /api/evaluate/test-anthropic ANTHROPIC_API_KEY の smoke チェック (P-7)。/api/evaluate/test-gemini をミラー。

🤖 新規 CLI エントリポイント

ファイル CLI ノート
AGENTS.md Codex / Aider / 汎用 完全指示は CLAUDE.md を指す。
GEMINI.md Gemini CLI セッション開始時に Gemini が自動ロード。

[1.8.0] — 2026-05-08

ハードニング、リファクタ、SDD ブートストラップ。3 件の高重大度修正 (A1、A2、A3)、4 件の中重大度 (B1–B4)、6 件のクリーンアップ、親 career-ops v1.7.0 サーフェスの監査、server split-by-concern (P-2 フェーズ 1)、Playwright ブラウザ smoke ハーネス、docs/.claude/ 下の完全な SDD 基盤。

🔥 高重大度修正

  • fix(deep): inline cv/profile/mode files for Anthropic SDK calls (REVIEW-A1)/api/deep/api/mode/:slug は以前モデルに「これらのファイルを最初に読む」と指示していましたが Anthropic SDK にはファイルシステムがありません。出力は中身が空でした。新規 bundleProjectContext({ modeSlugs })cv.mdconfig/profile.ymlmodes/_shared.md、mode テンプレートを読み、各 16 KB で切り詰め、プロンプトに <project_context> ブロックを前置。ライブ検証済み: claude-sonnet-4-6 から deep-research 呼び出しに対し 26 KB の grounded markdown レスポンス。
  • fix(runner): SIGKILL escalation after SIGTERM grace period (REVIEW-A2)runNodeScriptstreamNodeScript は以前 timeout / client-disconnect で SIGTERM のみを送信していました。syscall (DNS、ブロックされた socket) で stuck になった子プロセスはこれを無視し、SSE 接続が Node の GC が刈り取るまでハング。各パスは 5 秒のウォッチドッグを腕装し SIGKILL にエスカレート。Promise が常に resolve するように。
  • fix(runner): max-runtime cap on streaming endpoints (REVIEW-A3) — 全 SSE スクリプト runner (/api/stream/{scan,liveness,pdf}) がハードな 30 分上限を持つように。期限切れ時: event: error { message: 'maximum runtime exceeded' } を発し、A2 ウォッチドッグ経由で子を kill、レスポンスを終了。

🛡️ 中重大度修正

  • fix(preview): per-hop redirect validation in /api/pipeline/preview (REVIEW-B1)redirect: 'follow' から手動 redirect-walking に切り替え。各 Location ヘッダは isValidJobUrl で再検証;3 ホップで上限。敵対的なボードが loopback / プライベート IP / file:// にバウンスできなくなりました。拒否パスを 4 つの新規テストでカバー。
  • refactor(keys): hasGeminiKey helper unifies LLM-key checks (REVIEW-B2) — ルートハンドラの直接 process.env.GEMINI_API_KEY 読み取りを lib/anthropic.mjshasGeminiKey() に置換。hasAnthropicKey() 形状をミラーし一貫性とモック容易性を確保。
  • feat(scanners): thread AbortSignal through hh.ru, Habr, Greenhouse, Ashby, Lever (REVIEW-B3) — SSE クライアントが scan 中に切断した際、進行中の HTTP fetch が全クエリを完了まで走らせてイベントを drop する代わりに abort されるように。runRuScanrunEnScanopts.signal を受け取り、/api/stream/scan-{ru,en} の SSE ハンドラが AbortController を作成し res.close で abort。
  • test(anthropic): log-guard test prevents future API-key leaks via console (REVIEW-B4)runAnthropic のハッピー + エラーパス中の全 console.{log,info,warn,error,debug} 呼び出しを捕捉、出力ゼロと canary key 文字列が決して現れないことをアサート。将来の console.log(opts) 回帰に対する多層防御。

🧹 低重大度ポリッシュ

  • fix(parsers): defense-in-depth URL gate inside addPipelineUrl (REVIEW-C4) — ルートレベル isValidJobUrl を補完するパーサレベルでの非 http(s) 値拒否。より厳格なルールを望む呼び出し元向けにオプションの opts.validate
  • docs(readme): badge "tests-88 passed" → "tests-277 passed" (REVIEW-C3) — 桁が 1 つズレていました。
  • test(i18n): missing-keys diff grouped by locale (REVIEW-C6)tests/i18n-coverage.test.mjs がギャップを見つけた際、出力が混在行ではなく [ru] (3): foo, bar, baz に。
  • docs(review): C1 closed as resolved-on-inspection — サニタイザ正規表現は既に \x00-\x08 の hex 形式;review エントリはツールレンダリングのアーティファクトでした。

🏗️ P-2 フェーズ 1 — server split-by-concern

server/index.mjs は 1230 LOC で 800 行天井を大きく超えていました。挙動変更なしで focused モジュールに分割。283 unit テスト全てが各ステップで緑のまま。

  • server/lib/security.mjsisValidJobUrlstripDangerousMarkdownsanitizeJobDescriptionisPubliclyExposed。外部コンシューマの後方互換のため index.mjs から re-export。
  • server/lib/prompts.mjsbundleProjectContextbuildEvaluationPromptbuildDeepPromptbuildModePromptbuildApplyChecklist
  • server/lib/store.mjssafeReadAppssafeReadPipelinesafeListReportscheckProfileCustomizedensureRussianPortalsDefaults
  • server/lib/routes/scan.mjs/api/stream/scan-{ru,en}/api/scan-ru/config/api/scan-results 用の registerScanRoutes(app)
  • server/lib/routes/runners.mjs — バッファ /api/run/* テーブル、ストリーミング /api/stream/{scan,liveness,pdf}、生成 PDF list/download 用の registerRunnerRoutes(app)
  • server/lib/routes/content.mjs — CV / Profile / Portals / Modes 用の registerContentRoutes(app)

index.mjs は今や 762 LOC (-38%、800 上限以下)。フェーズ 2 では tracker、pipeline、reports、jds、llm (evaluate/deep/mode)、health をルートモジュールに抽出。オーケストレータは <500 LOC を目標。

🔍 親 career-ops v1.7.0 監査

ユーザーが親プロジェクトを v1.7.0 に更新。消費される全サーフェスを監査 — UI は完全に互換。注目すべき発見は docs/architecture/DATA-FLOWS.md に文書化:

  • Modes カタログが 7 → 19 ファイルに成長。UI の MODE_ALLOWLIST は意図的に 7 つだけを surface (他は Claude-Code 専用)。意図的な狭いスコープを説明するコメントを追加。
  • portals.yml スキーマ確認: tracked_companies (96 エントリ、87 有効、71 が API あり)。EN scanner はこれを正しく読む;レガシー companies キーも引き続きサポート。
  • 今日消費されない新規親サーフェス: dashboard/ (Go プログラム)、update-system.mjsgenerate-latex.mjsanalyze-patterns.mjsliveness-core.mjsfollowup-cadence.mjstest-all.mjs、ローカライズされた mode サブディレクトリ (de/fr/ja/pt/ru)。
  • ライブの /api/dashboard/api/health/api/modes/api/portals/api/profile/api/cv/api/jds/api/reports/api/tracker/api/pipeline/api/evaluate/api/deep/api/stream/scan-en 全てが緑検証済み。

🤖 SDD / GSD ブートストラップ

career-ops-ui は GSD パイプライン (superpowers@claude-plugins-officialgsd-* skill) と整合する完全な Spec-Driven Development 基盤を持つように。

  • CLAUDE.md (ルート) — プロジェクトレベルのエージェントシステムプロンプト: スタック、GSD パイプライン、hard rules (親契約、セキュリティエンベロープ、--no-verify 禁止)、慣例、親プロジェクト境界。
  • .aiignore — AI エージェント用除外リスト: ベンダー、バイナリ、親ユーザーデータ、.planning/.env、ロケール重複。
  • .claude/agents/ — 3 つのプロジェクト固有サブエージェント定義:
    • web-ui-route-reviewer.md — 新ルートを SSRF、CSP、サニタイザ、親書き込み契約、慣例、テストに対してゲート。
    • spa-view-reviewer.md — CSP-safe DOM、i18n、ルーター登録、アクセシビリティ。
    • test-isolation-reviewer.md — テストが CI 分離されている (親プロジェクトを前提としない、ライブネットワークなし、ポート衝突なし) ことを検証。
  • .claude/commands/ — slash-command スタブ: /sdd-status/codebase-tour
  • docs/ ツリー — 全て英語:
    • PROJECT.md — 何を/なぜ/誰のために、スコープ、制約、成功基準。
    • ROADMAP.md — 現在のマイルストーン + 完了履歴 + バックログ。
    • sdd/SDD-GUIDE.mdgsd-* skill にマッピングされた discuss → spec → plan → execute → verify → review パイプライン。
    • sdd/CONVENTIONS.md — モジュールシステム、命名、ルート、サニタイザ、クライアントパターン、i18n、エラー、ロギング、テスト、コミット、ブランチ、CSS。
    • architecture/OVERVIEW.md — トップレベル図、レイヤ、ブートシーケンス、不変条件、“where to look first when…” チートシート。
    • architecture/SERVER.mdserver/lib/*.mjs のファイル毎マップ (P-2 分割で更新)。
    • architecture/FRONTEND.md — SPA 構造、view インベントリ、グローバル、“how to add a view”。
    • architecture/API.md — 全 /api/* ルートの完全インベントリ。
    • architecture/DATA-FLOWS.md — 親プロジェクトの全 read/write、明示的ユーザーアクション契約付き。
    • reviews/REVIEW-2026-05-07.md — この changelog の修正を生んだ静的レビュー。

🔒 セキュリティ & リポジトリ衛生

  • chore(.gitignore): comprehensive defense-in-depth patterns — env バリアント、IDE フォルダ、GSD スクラッチ (.planning/)、ユーザー毎エージェント設定 (.claude/settings.local.json.claude/cache/.claude/state/.claude/memory/)、Playwright アーティファクト (playwright-report/test-results/.playwright/trace.zip)、heap/CPU プロファイル、未出荷ツールのロックファイル、拡張された macOS Finder ノイズ、汎用シークレットパターン (secrets.jsoncredentials.json*.pem*.key) をカバー。

🧪 テスト

  • 283 unit テスト (以前 277): +11 新規 (B1 redirect 拒否で 4、hasGeminiKey で 1、runAnthropic log-guard で 1)。
  • 5 Playwright ブラウザ smoke テスト (新規、npm run test:e2e:browser で opt-in): ダッシュボードレンダリング + バージョンフッタ、ダッシュボード → scan → pipeline → cv ナビゲーション、言語切替永続化、404 view、health ページレンダリング。Playwright は親の node_modules 経由で解決 — 新規依存なし。
  • カバレッジは約 93% 行 / 約 83% 分岐を維持。

📝 新規 / 更新された package.json スクリプト

スクリプト 目的
npm run test:e2e:browser in-process サーバーに対し Playwright smoke ハーネスを実行 (5 テスト)。

🔧 触れたファイル

+ CLAUDE.md                                    +  .aiignore
+ docs/PROJECT.md                              +  docs/ROADMAP.md
+ docs/sdd/SDD-GUIDE.md                        +  docs/sdd/CONVENTIONS.md
+ docs/architecture/OVERVIEW.md                +  docs/architecture/SERVER.md
+ docs/architecture/FRONTEND.md                +  docs/architecture/API.md
+ docs/architecture/DATA-FLOWS.md              +  docs/reviews/REVIEW-2026-05-07.md
+ .claude/agents/web-ui-route-reviewer.md      +  .claude/agents/spa-view-reviewer.md
+ .claude/agents/test-isolation-reviewer.md
+ .claude/commands/sdd-status.md               +  .claude/commands/codebase-tour.md
+ server/lib/security.mjs                      +  server/lib/prompts.mjs
+ server/lib/store.mjs
+ server/lib/routes/scan.mjs                   +  server/lib/routes/runners.mjs
+ server/lib/routes/content.mjs
+ tests/playwright-smoke.mjs

~ .gitignore                                   ~  README.md (badge fix)
~ package.json (1.7.2 → 1.8.0)
~ server/index.mjs (1230 → 762 LOC)
~ server/lib/runner.mjs (SIGKILL escalation, max-runtime cap)
~ server/lib/anthropic.mjs (hasGeminiKey)
~ server/lib/parsers.mjs (URL gate in addPipelineUrl)
~ server/lib/ru-scanner.mjs                    ~  server/lib/en-scanner.mjs
~ server/lib/sources/{hh,habr,greenhouse,ashby,lever}.mjs (signal threading)
~ tests/anthropic.test.mjs                     ~  tests/i18n-coverage.test.mjs
~ tests/pipeline-preview.test.mjs

[1.7.2] — 2026-05-04

Help center、UI 内 App settings、モバイルサイドバー、単一 Scan ボタン、全 prompt-builder の「結果を表示」ショートカット。

✨ 新機能

  • feat(help): in-app user guide (/#/help) — 新規サイドバーエントリからアクセス可能な長文 Markdown ドキュメント。各ページをステップバイステップでカバー: クイックスタート、CV エディタ、Profile、Scan フィルタ、Pipeline preview、Evaluate、Deep research、Apply、Tracker、Reports、7 mode 全て、Activity log、Health、セットアップヒント。<h2> 見出しから自動構築される sticky 目次、同期 DOM 構築 (race なし)。サポートする 8 ロケール全てにローカライズ。
  • feat(config): in-UI App settings page (/#/config) — ブラウザから ANTHROPIC_API_KEYANTHROPIC_MODELGEMINI_API_KEYGEMINI_MODELHH_USER_AGENTPORTHOST を編集。親プロジェクト.env ファイルに書き込むため career-ops Node スクリプトと web-ui の dotenv ローダの両方が同じソースを取得します。シークレットキーは読み取り時にマスク (先頭/末尾 4 文字)。Model フィールドはキュレートされたリストの dropdown (claude-sonnet-4-6 / claude-opus-4-7 / claude-haiku-4-5 / gemini-2.0-flash 等)。空値はキーを削除。値は実行中の process.env に即座に適用 — ほとんどの設定で再起動不要。
  • feat(modes): "⚡ Show result" button alongside "Copy prompt" — manual モードでプロンプトが生成された時、ユーザーは LLM 結果を得るために入力を再タイプする必要がなくなりました。新ボタンは同じフォームを run: true で再送信し、キーが構成されていない場合は明確なトースト (Set ANTHROPIC_API_KEY or GEMINI_API_KEY in .env first) にフォールスルー。/#/deep/#/project/#/training/#/followup/#/batch/#/contacto/#/interview-prep/#/patterns で動作。

🐛 UX + UI 修正

  • fix(scan): single Scan button replaces three (Scan all + EN + RU) — 圧倒的な選択肢、99% のケースで同一デフォルト。統合された 🌐 Scan ボタンが有効な全ソースを実行。Help ドキュメントを 8 ロケールで更新。
  • fix(ui): mobile sidebar drawer — ビューポート <900px がトップバーにハンバーガーボタン (☰) を取得;body.sidebar-open がサイドバーをスライドインさせる CSS transform をトグル。Backdrop dim + クリックでクローズ。アンカークリック + hashchange で自動クローズし、ユーザーは drawer が畳まれた状態で新ページに着地。大きなビューポートは影響なし。
  • fix(server): footer version reflects web-ui, not the parent VERSION/api/health が web-ui 自身の package.json を読むように。フッタは親のバージョンファイルから古い 1.6.0 を漏らさなくなりました。親の VERSION は引き続き parentVersion として別途 surface。

📦 新規 REST エンドポイント

メソッド パス 目的
GET /api/help/:lang リクエストされたロケールの Markdown ユーザーガイドを返却、en.md にフォールバック。Path-traversal セーフ。
GET /api/config 全既知 env キーの現在値を返却;シークレットマスク。
POST /api/config 指定キーを親プロジェクトの .env に書き込み、各値を検証、process.env にライブ適用。

🌐 i18n

  • nav.helpnav.confighelp.*config.*deep.showResultdeep.needKeyscan.btnRun にわたる 30+ 新キー。全 8 ロケール充足。

🧪 テスト

  • tests/help.test.mjs (12 ケース) — 全サポートロケールが実質的 markdown を返却、EN が各ページ slug をスポットチェック、未知 lang → EN フォールバック、path-traversal サニタイズ、各ロケールが cv.md / profile.yml / .env を参照。
  • tests/help-ui.test.mjs (9 ケース) — view ファイル登録、サイドバーエントリ、全ロケールの i18n キー存在、各ロケールの docs ファイル存在、EN/RU help が 14 個の正規セクション、全 #/foo ルートカバレッジ、deep + mode-page の Show-result 配線。
  • tests/env-config.test.mjs (18 ケース) — parseEnvmaskSecretvalidateConfigupdateEnvFile (ブートストラップ、コメントを保持しつつ in-place 書き直し、空値削除、必要時の quote) の純関数テスト。
  • tests/config-endpoint.test.mjs (8 ケース) — GET がシークレットをマスク / env パス返却;POST が親 .env に書き込み;live process.env 適用;空値で unset;未知キー + 不正形式 Anthropic キーを 400 で拒否。

📊 統計

  • テスト: 233 → 277 (+44 新規テストファイル 4 つにわたって)。
  • E2E: 20 smoke + 23 包括 = 43 Playwright ステップ、全緑。
  • カバレッジ: 93.5% 行 / 82.6% 分岐 / 93.7% 関数 (不変 — 新コードは完全にテスト済み)。

[1.7.1] — 2026-05-04

post-v1.7.0 作業を積み上げたパッチリリース: pipeline preview ペイン、Anthropic API 統合、スクロール可能なサイドバー、dotenv ローダ、動的 Active-companies リスト、CI ワークフローハードニング。

✨ Pipeline preview ペイン

  • /#/pipeline 刷新 — 左リスト + 右プレビューペイン。任意の URL をクリックしてサーバー側プロキシのスナップショットを fetch (GET /api/pipeline/preview がスクリプト/スタイル/タグを除去、8 KB で上限、isValidJobUrl で検証)。ライブフィルタ入力、“In queue” カウンタ、⚡ “Evaluate first” ヘッダボタン。各行のインライン ▶/✕ に加えてプレビューペインに完全な Evaluate / Open in tab / Delete。data-url + .pipeline-row + .pipeline-row-delete クラスによる安定したテストセレクタ。tests/pipeline-preview.test.mjs8 新規テスト (モックされた fetch、上流バインド不要)。

✨ Anthropic API 統合 — どこでも「Run live」

  • server/lib/anthropic.mjs — Anthropic Messages API 用ゼロ依存クライアント (claude-sonnet-4-6 デフォルト、ANTHROPIC_MODEL で上書き)。ANTHROPIC_API_KEY が設定されている場合、全 mode ページ (/#/deep/#/project/#/training/#/batch/#/contacto/#/interview-prep/#/patterns) が “⚡ Run live (Anthropic)” ボタンを プライマリ アクションとしてレンダリング — クリックでプロンプトを実行し Markdown をブラウザに描画 (Claude Code への引き渡しの代わり)。Gemini は Gemini キーのみ設定された場合のフォールバックとして残る。Manual モードはキーが全くなくても動作。tests/anthropic.test.mjs8 新規テスト

🐛 CI / pipeline 修正

  • fix(api): tighten pipeline URL validator (FIX-M7) — loopback ホスト名、長さ <10 または >2000、URL 内のホワイトスペースも拒否するように。
  • fix(server): actually load .env so HH_USER_AGENT / GEMINI_API_KEY hints workserver/lib/dotenv.mjs (35 行のゼロ依存ローダ) を追加し server/index.mjs の先頭に配線。スキャナコード内の runtime ヒントが遂に機能するように。6 新規テスト
  • fix(ui): scrollable sidebar — 6 グループ 18 ナビ項目が短いビューポートでオーバーフロー。.sidebar が薄いカスタムスクロールバー付きの overflow-y: auto を持つように。
  • fix(ui): make HH_USER_AGENT banner dismissible — その後、過剰だと判断し /scan から完全削除。Health ページのチェックは引き続き surface。
  • fix(scan): Active companies list is now collapsible + filterable + grouped — 87 タグのフラット表示は圧倒的でした。今や “▸ Active companies 87/71” トグルが順序付きリスト (✓ API-backed が先、○ websearch が次) + 検索フィルタを展開。
  • fix(test): isolate api.test.mjs + en-scanner.test.mjs from parent project — 両方が tmp プロジェクトルートを起動するため、web-ui と並んで親が checked out されていなくても CI が動作。
  • fix(workflow): publish-package version-match only on release events — main からの workflow_dispatch で tag/version チェックが失敗しなくなった。
  • fix(e2e): stable selector for pipeline row delete — アンカーラッパーを復元し data-url 属性を追加して e2e スイートが selector-stable に。

📦 新規 REST エンドポイント

メソッド パス 目的
GET /api/pipeline/preview?url=… サーバー側プロキシ: URL の可視テキストスナップショットを返却 (スクリプト/スタイル除去、8 KB 上限)、isValidJobUrl でゲート。

📊 このバッチ後の統計

  • テスト: 225 → 233 (v1.7.0 の上に +8)。
  • テストファイル: 25 → 26
  • E2E: 20 + 23 = 43 Playwright ステップ、全緑。

[1.7.0] — 2026-05-03

QA r5 駆動の 35 コミットによるハードニング + UX + 機能完成パス。3 層のセキュリティ (XSS サニタイズ、CSP、入力検証) が着地、欠落していた CRUD エンドポイントが全て埋まり、親プロジェクトブートストラップが完全自動化、UI が 9 つの新ページ を獲得 — Activity、再設計された Deep Research、サイドバーグループ化された 7 mode (project / training / followup / batch / outreach / interview-prep / patterns) で親 modes/ の 100% カバー。Pipeline がサーバー側 preview ペインを獲得。Anthropic API 統合により全 mode で “Run live” がワンクリックアクションに。テストカバレッジは 7322525 テストファイル、加えて 23 包括 Playwright e2e ステップ。GitHub Actions が CI / AI review / Release / Publish-Package ワークフローを出荷。

🔒 セキュリティ

  • fix(cv): sanitize CV markdown to block stored XSS in preview (FIX-C10)PUT /api/cv<script><iframe><object><embed><style><form><svg>on*= イベントハンドラ、javascript:/vbscript:/data:text/html URI を cv.md 書き込み前に除去。ボディは 1 MB で上限 (オーバーフロー時 413)。クライアント側 UI.md() を書き直し、任意の markdown 変換が走る前に全バイトをエスケープ。生 HTML が innerHTML に届くことはなくなりました。リンク href 属性は安全スキームの allowlist (http/https/mailto/tel/相対 + data:image のみ) で検証。strip ヘルパーと HTTP ラウンドトリップにわたる 17 新規テスト。
  • fix(server): add CSP and baseline security headers (FIX-L2) — 全レスポンスが X-Content-Type-Options: nosniffX-Frame-Options: DENYReferrer-Policy: same-origin を運ぶように。サーバーが loopback (HOST127.0.0.1/::1/localhost) を超えてバインドする場合、厳格な Content-Security-Policy が上に重ねられる: default-src 'self'script-src 'self' (unsafe-inline なし)、Google Fonts allowlist、connect-src 'self' で XSS 漏出をブロック。index.htmlrouter.js のインライン onclick ハンドラは addEventListener に移動し、厳格 CSP を維持。5 つの異なる HOST 値で CSP をゲートする 8 新規テスト。
  • fix(api): tighten pipeline URL validator (FIX-M7)POST /api/pipeline は以前 "not-a-url" を受け付け永続化していました。今や isValidJobUrl() が bare 文字列、<10 または >2000 文字、ホワイトスペースを含む URL、非 http(s) スキーム、loopback ホスト名 (localhost/127.0.0.1/::1) を拒否。FIX-M3 + FIX-M6 (無効で 400 を返却、成功時に deduped フラグ) を含む。
  • fix(server): actually load .env so HH_USER_AGENT / GEMINI_API_KEY hints work — 以前 runtime は「.env に HH_USER_AGENT を設定」とユーザーに伝えていましたが、サーバーはそのファイルを読まず、指示に従っても何も起きませんでした。35 行のゼロ依存 dotenv ローダ (server/lib/dotenv.mjs) を server/index.mjs の先頭に配線。コマンドライン上で設定された process-env 値が引き続き勝つため既存 CI 上書きが影に隠れない。親の .env.example に実際の Chrome User-Agent 例を含む HH_USER_AGENT ブロックを文書化。6 新規テスト。
  • fix(api): sanitize JD before prompt assembly (FIX-M5)POST /api/evaluate が Gemini 呼び出し前またはプロンプトのエコーバック前に ANSI エスケープ、制御バイト、インライン <script> タグを除去しホワイトスペースをトリム。50 KB 長上限。50 文字最小は サニタイズ後 テキストに対して走るため、長く見えるがほとんどがエスケープから成るプロンプトインジェクション試行は 400 で fail-fast。
  • fix(health): mask Node version + project root when HOST!=loopback (FIX-M1)/api/health が LAN 公開デプロイでホストをフィンガープリントしなくなりました。Loopback レスポンスはローカル診断用に値を保持。

✨ 新機能

  • feat: 7 new sidebar modes + grouped sidebar (FIX-C8) — UI ギャップなしで親の modes/ ディレクトリの 100% をカバー。新ルート: #/project (ポートフォリオプロジェクトアドバイザ)、#/training (コース / 資格評価)、#/followup (アプリケーション毎ケイデンス)、#/batch (並列 URL プロセッサ)、#/contacto (LinkedIn outreach ドラフタ)、#/interview-prep (ステージ固有準備)、#/patterns (拒否パターンアナライザ)。7 つ全てが単一の config 駆動 view factory (public/js/views/mode-page.js) と単一の汎用エンドポイント POST /api/mode/:slug を共有 — 将来の新規 mode 追加は 1 つの config 行 + 1 つの i18n ブロック。サイドバーを 6 グループに再編成: Sourcing / Decision / Application / Networking / Analytics / Setup。ナビ項目合計 18。tests/modes-endpoints.test.mjs の 12 新規テスト。
  • fix: bootstrap parent deps + russian_portals defaults (FIX-C4 + C9 + C12 + H2)bin/start.sh が fresh clone で親の node_modules (js-yaml、playwright、jsdom) と npx playwright install chromium をインストールするように。/api/stream/scan/pdf/liveness が箱から end-to-end で動作。createApp() がブート毎に portals.yml をプローブ — russian_portals: ブロックが欠落していればコメント付き文書化デフォルトを追記。冪等: 2 回目のブートは no-op。3 新規テスト。
  • fix: disable 9 dead portal slugs in template + health-check script (FIX-C3)templates/portals.example.yml が Ada / Factorial / Tinybird / Weights & Biases / Travelperk / Clarity AI / Forto / Vinted / Runway に enabled: false (各エントリに理由インラインコメント) でフラグを付けて出荷。新規インストールは 96 ではなく 87 社の生存スキャン。新規 web-ui/scripts/portals-health-check.mjs が全有効 careers_url を HEAD-probe し DEAD エントリと提案パッチリストをレポート (--json で JSON 出力)。3 新規テスト。
  • feat(activity): user-action log + Activity sidebar page — 全状態変更 API リクエストが data/activity.jsonl (タイムスタンプ、アクション動詞、ターゲット、成功フラグ、オプション詳細) にキャプチャ。アクションプレフィックスチップフィルタ (pipeline / cv / jd / evaluate / scan / stream / script)、アクション ✓/✗ バッジ、リフレッシュボタン付きの新規サイドバーエントリ Activity。5 MB で自動ローテーション。10 新規テストが middleware、read フィルタ、corrupt-line 耐性、GET /api/activity 自体の再帰ガードをカバー。
  • feat(deep): view Deep Research in browser + saved-results archive — Deep Research ページが (a) { run: true }GEMINI_API_KEY が設定されている時にプロンプトを Gemini でライブ実行し出力を interview-prep/{slug}.md に永続化、(b) 全保存 deep-research ファイルを相対タイムスタンプ付きクリック可能カードとして列挙、(c) 結果を Markdown としてレンダリングし結果毎に 📋 Copy / ⬇ Download .md / ↗ Open in tab アクションを提供。新規 REST サーフェス: GET /api/interview-prepGET /api/interview-prep/:nameDELETE /api/interview-prep/:name。7 新規テスト。
  • feat(cv): generate + download PDF in browser, with PDF archive — CV ページ上の新規 📄 Generate PDF ボタンがモーダルコンソールで /api/stream/pdf をストリーム。ERR_MODULE_NOT_FOUND / playwright エラー時、コピペ可能なブートストラップコマンドを surface。新規 “Generated PDFs” セクションが各成功実行後に自動ロードし、全 output/*.pdf↗ Open⬇ Download ボタン付きで列挙。新規 REST サーフェス: GET /api/output/pdfsGET /api/output/pdfs/:name。6 新規テスト。
  • feat(api): POST /api/tracker — append rows from the UI (FIX-H8) — ブラウザから data/applications.md に正規行を追記。company + role を検証、status を templates/states.yml に対して正規化、自動インクリメントのゼロ詰め #、company+role での dedup (大文字小文字無視)、markdown テーブルが壊れないよう notes のパイプをエスケープ。ファイルが空の時テーブルをブートストラップ。6 新規テスト。
  • feat(api): DELETE /api/jds/:name (FIX-H4) — シェルアウトなしで保存済み JD を削除。Path-traversal 文字はファイルシステム touch 前に除去;パラメータは .txt で終わる必要あり。../../etc/passwd 拒否を含む 5 新規テスト。
  • feat(api): POST /api/evaluate/test-gemini (FIX-H7) — ユーザーが実評価を待たずに API キーが機能することを確認できるよう、50 文字のダミー JD を gemini-eval.mjs 経由で実行する smoke テストエンドポイント。{ ok, code, sampleLength, sample } を返却。

🐛 バグ修正

  • fix(router): catch-all 404 view + i18n coverage guard (FIX-C7) — 未知ハッシュルートは以前サイレントにダッシュボードにフォールバックし、タイポや壊れたブックマークを覆い隠していました。今や #/totally-random-xyz が悪いパスを引用して返す専用 404 ページをレンダリングしダッシュボードへリンク。404 view はユーザールートと衝突しないよう router IIFE 内に登録。新規 tests/i18n-coverage.test.mjsvm.Context 内で stub window 付きで i18n.js を走らせ、プライベート DICT を expose し、173+ キー × 8 ロケールの各キーが populate されかつ非空であることをアサート。4 新規ルーターテスト。
  • fix(router): alias #/profile → settings (FIX-C2) — 内部ルート名は settings (nav.settings が “Profile” をレンダリング) ですが外部リンクと筋肉記憶は #/profile に行きます。今や両アドレスが同じ view に到達し、サイドバーのナビ項目はどちらでも光ります。2 新規テスト。
  • fix(health): unify Health/Doctor + flag template profiles (FIX-C6 + FIX-H6) — Health と Doctor は 2 つの異なる真実の源でした。今や /api/health が Doctor がレポートする全て (parent-deps、Playwright、dirs、profile-customized、HH_USER_AGENT) を expose。Profile customized チェックがプレースホルダ名 (Jane SmithAlex DoeJohn DoeYour NameTest User) と明示的な YAML パースエラーを検出。4 新規テスト。
  • fix(scan): warn on query↔negative collisions in RU config (FIX-H3)portals.ymltitle_filter.negative"PHP" を含み Senior PHP をターゲットとするクエリを持つ場合、全マッチがフィルタされユーザーは結果ゼロを見ます。loadConfig()warnings 配列を計算し;runRuScan() が scan 開始前に各 warning を SSE stderr 行として発します。2 新規テストが出荷デフォルトが箱から PHP-friendly のままであることを検証。
  • fix(scan): warn when HH_USER_AGENT is unset (FIX-H1)/scan ページが /api/health をプローブし、HH_USER_AGENT が空の時にアクション行上に黄色の警告カードを表示。RU scan をクリックする に hh.ru の 403 を知らせます。
  • fix(api): warn when POST /api/jds slug had unsafe chars stripped (FIX-M2) — 危険文字を除去する slug 正規化が warning フィールドを返却するように;純粋な大文字小文字/ホワイトスペースクリーンアップはサイレントを維持。サニタイズ後の空結果は 400。
  • fix(ui): clear global search on route change + button spinners (FIX-M4 + FIX-L1) — グローバル検索 input が hashchange でクリア (アクティブタイピングのガード付き)。新規 UI.withSpinner(button, fn) ヘルパーがローディング状態、ARIA、二重クリック防止を全非同期ボタンクリックに配線。Doctor / Verify / sync-check / Save CV / Normalize / Dedup / Merge ボタンで既に採用。
  • fix(ui): make sidebar scrollable so 18 nav items always reach the footer — FIX-C8 のグループ化サイドバーが短いビューポートでオーバーフロー;ボトム項目 (Activity / Health) がクリップされていました。.sidebar が薄いカスタムスクロールバー付き (WebKit + Firefox) の overflow-y: auto を持つように。フッタは既存の margin-top: auto で pin されたまま。
  • fix(ui): empty modal-title placeholder (FIX-H9)index.html のハードコード英語 "Title" 文字列が消え、モーダルオープン中に見えていた短いレースウィンドウをクローズ。

🌐 i18n

  • 173+ 翻訳キー × 8 サポートロケール (enespt-BRkojaruzh-CNzh-TW)。404 ページ、activity log、deep research、PDF フロー、セキュリティ警告、tracker mutation、apply rename にわたる新規キーを全ロケールに追加。カバレッジは tests/i18n-coverage.test.mjs で強制 — 全キーが全サポートロケールで非空値を持つ必要があるか CI が失敗。

⚙️ DevOps

  • テスト数: 73 → 201 (23 テストファイルにわたって +128 テスト)。残る単一失敗テスト (runEnScan: dry-run end-to-end across multiple sources) は Greenhouse/Ashby/Lever ライブ API レスポンスに依存する既存 flake。
  • 包括 Playwright e2e (tests/e2e-comprehensive.mjs、23 ステップ): 完全なユーザー旅程を歩く — CV 保存 → preview → PDF 生成 → 全 7 つの新 mode → tracker フィルタ → activity log → 404 → モーダル ESC → サイドバースクロール → Ctrl-K フォーカス → 検索クリア → profile alias → 言語永続化。
  • GitHub Actions (.github/workflows/):
    • ci.yml — Node 18/20/22 マトリクスでの unit + integration テスト、i18n カバレッジゲート (全キー × 8 ロケールが非空である必要)、全 Playwright e2e を PR 毎に。
    • ai-review.yml — 全 PR で Claude Code AI レビュー。メンテナがマージ権限を保持;Claude は提案のみ。skip-ai-review ラベルでスキップ。
    • release.ymlv*.*.* タグが push されると GitHub Release を自動公開;リリースノートは CHANGELOG.md からスライスされるため、全 8 言語バリアントが正規ソースのまま。
  • CSP フレンドリ UI: index.htmlrouter.js から全インライン onclick ハンドラを削除。厳格 script-src 'self' ポリシーが機能を壊さずに強制可能に。

📦 新規 REST エンドポイント

メソッド パス 目的
GET /api/activity ユーザーアクションイベント一覧、新しい順
GET /api/interview-prep 保存済み Deep Research ファイル一覧
GET /api/interview-prep/:name 単一の Deep Research ファイル読み取り
DELETE /api/interview-prep/:name Deep Research ファイル削除
GET /api/output/pdfs 生成済み PDF 一覧
GET /api/output/pdfs/:name PDF を添付としてストリーム
POST /api/tracker applications.md に行を追記
DELETE /api/jds/:name 保存済み JD を削除
POST /api/evaluate/test-gemini Gemini API キーを smoke テスト
POST /api/mode/:slug 7 つの新 mode (project / training / followup / batch / contacto / interview-prep / patterns) 用の汎用プロンプトビルダー

[1.6.0] — 2026-05-02

web UI の初回公開リリース。このベースライン時点での機能インベントリは README.md を参照してください。