Журнал изменений

GitHub

Каждое значимое изменение, релиз за релизом. Тот же файл публикуется в репозитории и переведён на все 19 языков.

[1.135.0] — 2026-08-11

Паритет с родительским career-ops v1.26.0 — пять новых источников сканирования без авторизации, а также исправления корректности для четырёх досок, уже реализованных в web-ui. Реестр теперь насчитывает 78 источников = 73 EN + 5 RU (ALL_ADAPTERS 73).

Добавлено

  • Пять новых источников сканирования (каждый — источник + адаптер + CI-изолированный сьют; они появляются в фильтре Source на #/scan и на лендинге cvstart.org):
    • join (JOIN) — доска JOIN компании из встроенного в Next.js __NEXT_DATA__ на join.com/companies/<slug> (закреплён по хосту, с лимитом страниц).
    • getro (Getro) — портфельные доски венчурных «talent-network» через публичный POST API api.getro.com, постранично от новых к старым; каждая вакансия приписывается портфельному работодателю, а не фонду.
    • consider (Consider) — портфельные доски венчурных фондов на getconsider.com через POST на том же источнике (origin); конфигурируемый хост закреплён структурным SSRF-guard’ом (только публичный HTTPS-хост).
    • joinup (JOINUP) — швейцарская доска joinup.ch, чтение отрендеренной на сервере (SSR) самой новой страницы; при поломке скрапера — fail-closed.
    • remotli (Remotli) — remotli.ch, удалённые роли в швейцарских компаниях (зарплаты в CHF); отдаёт собственный apply-URL ATS работодателя, поэтому кросс-листинги дедуплицируются.

Исправлено

  • a16z Speedrun больше не прерывает скан всей доски целиком при временном сбое — запросы страниц теперь идут через общий fetchJsonWithRetry (ограниченные повторы только при временных 429/5xx/таймауте, но не при устойчивой 4xx), а бюджет страниц пересчитан под страницу из 50 вакансий.
  • arbeitsagentur переведён на API Jobsuche v6 (/pc/v6/jobs) — старый эндпоинт v4 отдаёт 404; форма ответа была переименована, а фильтрация по удалёнке теперь сужается на стороне сервера.
  • thehub переведён на API v2 jobsandfeatured; строки не содержат даты публикации и исключены из фильтра по возрасту.
  • hackernews теперь надёжно находит ежемесячный тред «Who is hiring?», фильтруя поиск через Algolia по тегу учётной записи author_whoishiring вместо текстового запроса.

Примечания

  • Не портировано (web-ui уже безопасен, поглощается relay’ем или относится только к CLI): Unicode-совместимые ключи дедупликации ролей / сопоставления компаний (группировка повторов в web-ui уже ключуется по компании в обычном нижнем регистре, поэтому разные не-латинские работодатели никогда не схлопываются в один ключ); сигнал задержки отказов followup + доработки company-funded (проксируются только на чтение, fail-soft); переопределяемые через env пути скана и разбор --flag=value (web-ui запускает сканеры в процессе); рефакторинг унификации User-Agent (web-ui уже централизует его); а также пункты, относящиеся только к CLI (реестр недоверенного контента, oferta/offer-prep, doctor, изменения шаблонов сопроводительного письма/резюме).

[1.134.1] — 2026-08-05

Усиление валидации — исправления, выявленные полным аудитом проекта.

Исправлено

  • successfactors больше не отбрасывает уже собранные вакансии при сбое в середине скана (регрессия из портирования dead-board-throw в v1.134.0) — в цикле его пагинации не было try/catch, поэтому сбой на странице 2 и далее (после успешной первой страницы) выбрасывал ошибку и терял всё уже собранное; а если этим сбоем был 404 (вышедший за диапазон startrow), en-scanner на несколько дней помечал живого тенанта как мёртвого. Теперь поведение зеркалирует phenom/radancy: сбой на странице 0 всё ещё выбрасывает ошибку (мёртвая доска), но сбой на более поздней странице сохраняет частичные результаты.
  • Фильтр-чипы #/scan теперь управляются с клавиатуры (WCAG 2.1.1) — чипы фасетов (и чип «очистить») были элементами span с обработчиком клика, но без tabindex/роли, поэтому пользователи клавиатуры и скринридеров не могли до них добраться или переключить их. Теперь у них есть role="button", tabindex="0", aria-pressed и активация по Enter/пробелу.
  • Три хардкоженные англоязычные строки теперь локализованы — подсказка бейджа доверия на #/scan, заголовок столбца релокации на #/scan и заголовок столбца оценки на #/dashboard были обычными строковыми литералами, которые гейт паритета i18n не мог увидеть (они никогда не были ключами), поэтому во всех неанглийских локалях они оставались на английском. Теперь это scan.trustTip + scan.col.reloc (2 новых ключа) и повторное использование track.col.score, со статической source-гардой.

[1.134.0] — 2026-08-05

Паритет с родительским career-ops v1.25.0.

Добавлено

  • Новый источник сканирования: getManfred (manfred) — общедоступный по всей доске фид испанских/европейских технических вакансий с публикуемыми зарплатами, из www.getmanfred.com/api/v2/public/offers (без авторизации, закреплён по хосту + только HTTPS, полный каталог одним запросом). Источник + адаптер + CI-изолированный сьют (tests/sources-manfred.test.mjs); реестр теперь насчитывает 73 источника = 68 EN + 5 RU (ALL_ADAPTERS 68). Появляется в фильтре Source на #/scan и на лендинге cvstart.org.

Исправлено

  • Фид a16z Speedrun незаметно урезался до 50 вакансий (#2404) — фид ограничивает страницу 50 записями, но источник запрашивал PER_PAGE = 100, поэтому пагинация останавливалась после первой страницы. Исправлено на 50.
  • Мёртвые доски теперь выбрасывают ошибку вместо того, чтобы читаться как «живые, но пустые» (#2379) — cryptocurrencyjobs, phenom, radancy, successfactors: сбой запроса, при котором ни один запрос так и не завершился успешно, теперь выбрасывает ошибку (так что здоровье #/portals и скан фиксируют реальный сбой), вместо того чтобы проглатывать его как пустой список; сбой в середине скана после хотя бы одного успеха сохраняет частичные результаты.
  • workable теперь использует публичный widget API (#5ab8425) — переключено на apply.workable.com/api/v1/widget/accounts/<slug>, который отдаёт полный список вакансий крупного аккаунта за один запрос, поэтому крупные аккаунты больше не урезаются.

Примечания

  • Не портировано (только для CLI или не зеркалируется в web-ui): перф-переписывание группировки заголовков в detect-reposts #2389; исправления Unicode-ключей компаний (собственная дедупликация трекера web-ui уже безопасна для не-латиницы); scan --since; cv-facts; проход аудита шаблона CV / PDF; doctor; директива о недоверенном контенте в modes.

[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', {}, …) как varargs, но UI.el(tag, attrs, children) принимает children как один узел или массив, поэтому отрисовывался только первый столбец (Компания) — теперь ячейки передаются как массив. Проверено вживую в браузере: 11 компаний из четырёх фидов отрисовываются со столбцами Компания / Сигнал финансирования / Источник / Дата и рабочими ссылками на доказательства, ноль ошибок в консоли. Пустой проход теперь также показывает диагностику по каждому источнику, так что тихий новостной день можно отличить от заблокированного фида.
  • Регрессионные гарды в tests/parity-routes-v1133.test.mjs: поддельный родительский скрипт теперь отдаёт реальную форму вывода companies (исходная фикстура зеркалировала неверную форму candidates — именно поэтому баг и прошёл в релиз), плюс статические source-канарейки, проверяющие, что funded.js читает res.companies (никогда res.candidates) и строит строки таблицы с дочерними элементами-массивом (+1 → 2144).

[1.133.0] — 2026-08-01

Добавлено

  • Обнаружение профинансированных компаний (#/funded, паритет с родителем #2117) — новый read-only вид, транслирующий родительский career-ops company-funded.mjs через GET /api/company-funded: предварительно проверяемый (review-first) список недавно профинансированных компаний, обнаруженных из публичных, закреплённых по хосту фидов о финансировании (TechCrunch, PR Newswire, The Guardian, Hacker News). Релей запускает скрипт с --json --dry-run (JSON в stdout, без записи файлов), никогда не прокидывает пользовательский ввод в --sources (нет SSRF-поверхности сверх собственных фиксированных фидов родителя), несёт llmRateLimit и запускается пользователем (кнопка Discover, никогда при монтировании). Новый модуль маршрута server/lib/routes/funded.mjs (32-й) + public/js/views/funded.js, в разделе Sourcing.
  • Еженедельный дайджест интервью (#/interview-digest, паритет с родителем #2129/#2130) — новый read-only вид, транслирующий родительский zero-LLM weekly-digest.mjs через GET /api/interview/weekly-digest: механическая сводка interview-prep/sessions/*.md — с какими компаниями и на каких раундах вы проходили интервью на этой неделе, повторяющиеся компетенции и оценочные (best-effort) открытые пробелы. Опциональный диапазон ?from=&to= прокидывается ТОЛЬКО если ОБА значения — валидные YYYY-MM-DD; пустой диапазон — валидный дайджест available:true (не сбой). Добавлено в server/lib/routes/interview.mjs + public/js/views/interview-digest.js, в разделе Analytics.
  • Оба релея следуют устоявшемуся fail-soft-контракту { available:false } (как /api/stats/lifetime), когда родительский скрипт отсутствует (CI, автономные установки), так что каждый вид показывает честную заметку. 26 новых i18n-ключей ×17 локалей; CI-изолированный сьют tests/parity-routes-v1133.test.mjs (+5 → 2143: успешный passthrough, прокидывание --from/--to, гарантия read-only --dry-run и путь fail-soft при ошибке скрипта).

Примечания

  • Родительский career-ops продвинулся дальше v1.24.0: страница Follow-up Tracker Next.js-приложения web/ (#1422) и бэкенд-рендер PDF (#2182) — не портированы: у web-ui уже есть собственный релей follow-up (v1.117.0) и раннеры PDF, а лежащее в основе укрепление followup-cadence.mjs (отклонение невозможных дат, null-safe addDays, разбор legacy-буллетов) достаётся бесплатно через shell-out релей. Изменения 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 строк). Подсистема — renderResults, buildChipRow, билдеры строк/фасетов, отрисовщики опций и зеркало реестра FALLBACK_SOURCES — переезжает в фабрику window.ScanResults.create(ctx), замыкающуюся на объект контекста, который передаёт вид. Без изменений поведения — функции перенесены дословно, а их переменные замыкания перепривязаны на ctx.*; scan.js теперь ~906 строк (запланирован второй проход извлечения к цели в 800 строк).
  • Новый браузерный регрессионный гейт — tests/playwright-scan-filters.mjs засевает эталонный data/last-scan.json и прогоняет каждый фильтр #/scan, проверяя точные счётчики строк, так что извлечение верифицировано на реальном поведении браузера.
  • Баннер README облегчён — длинная построчная narrative-стена «Последний релиз» по версиям упраздняется в пользу однострочного резюме + ссылки на полный журнал изменений (CHANGELOG.ru.md).

[1.131.2] — 2026-07-31

Изменено

  • app.css разделён на три упорядоченных таблицы стилей (техдолг по контракту размера файла — единый файл разросся до ~1990 строк, далеко за жёсткий лимит в 800 строк). Теперь это app.css (~672 — a11y, дизайн-токены/тема, sidebar, main, кнопки, content-shell), components.css (~595 — карточки, гриды, пагинатор, бейджи, таблицы, формы, лог/консоль, markdown, переключатель языка, chip-фильтр, баннер соединения) и overlays.css (~737 — toast, шторка уведомлений, модалка, разное/адаптивность, RTL-зеркалирование [dir="rtl"], docs-fab, usage-hud), каждый в пределах жёсткого лимита.
    • Разрез непрерывный и в исходном порядке, поэтому каскад побайтово идентичен файлу до разделения; index.html подключает все три как упорядоченные <link>. Без изменений поведения, разметки или i18n.
    • Тесты, проверяющие CSS, теперь читают конкатенацию через общий хелпер tests/helpers/css.mjs::loadAppCss(). Новый tests/css-modularization.test.mjs фиксирует разделение (файлы существуют · каждый ≤ 800 строк · порядок ссылок в index.html) → сьют 2138. Проверено вживую в браузере: все три таблицы стилей парсятся и их правила применяются.

[1.131.1] — 2026-07-31

Исправлено

  • Согласованность host-pinning адаптеров на двух источниках v1.130.0 (доработки по code-review, defense-in-depth; поведение для валидных входных данных не меняется):
    • Адаптер a16z-speedrun-talent теперь повторно валидирует override api: / a16z-speedrun-talent: в buildEndpoint (HTTPS + точное совпадение хоста speedrun-talent-network.com) и откатывается на канонический фид при сбое проверки — паритет с адаптером cryptocurrencyjobs, так что значение с чужим хостом никогда не попадает в слот запроса (ранее полагался исключительно на гард assertSpeedrunUrl на момент запроса). Проверка точного хоста теперь единый экспортируемый SPEEDRUN_TALENT_HOST_RE, общий для гарда и адаптера.
    • Парсер cryptocurrencyjobs — cleanUrl теперь использует тот же гард точного совпадения хоста, что и assertCryptocurrencyJobsUrl и override адаптера (было endsWith, который принимал поддомены). Парсер никогда не более permissive, чем SSRF-гард: ссылка на элемент с sub.cryptocurrencyjobs.co отбрасывается.
    • +2 теста → сьют 2135.

[1.131.0] — 2026-07-31

Добавлено

  • CRM-доска со вкладками стадий на #/tracker (портировано из вида /pipeline веб-приложения родителя). Полоска funnel-чипов трекера и дропдаун статуса заменены на полосу вкладок стадий: вкладка All плюс по одной вкладке на каждый канонический статус — Evaluated · Applied · Responded · Interview · Offer · Rejected · Discarded · SKIP · Hired — каждая показывает живой счётчик за всю историю, включая стадии с нулевым счётчиком, чтобы всегда была видна вся воронка (вид CRM). Активная вкладка управляет фильтром; повторный клик по ней сбрасывает обратно на All. Строки сохраняют тон оценки, легитимность, возможности PDF и отчёта, а ячейка компании теперь показывает брендовый логотип, если логотипы включены (по умолчанию выключены → ноль дополнительных запросов).
    • Новый read-only маршрут GET /api/tracker/stages возвращает канонический перечень стадий воронки (метки по порядку) + карту свёртки алиасов, источник — server/lib/states.mjs (templates/states.yml, со встроенным fallback) — так что клиент никогда не хардкодит whitelist статусов. Легаси-ответ GET /api/tracker без параметров не изменился (только { rows }).
    • Новая чистая, покрытая юнит-тестами клиентская библиотека public/js/lib/tracker-stages.js раскладывает строки по стадиям сервера, устойчива к случайному markdown-жирному начертанию и локализованным алиасам (например, aplicado → Applied). Вкладки доступны (role tablist/tab, aria-selected, зона клика ≥44 px, счётчики в accessible name каждой вкладки). Новых i18n-ключей нет. Сьют — 2133 теста.

[1.130.0] — 2026-07-31

Добавлено

  • Два новых источника сканирования, портированных из родительского career-ops v1.24.0 (in-process, без новых зависимостей; оба появляются в фильтре Source на #/scan и на лендинге cvstart.org):
    • a16z Speedrun (a16z-speedrun-talent, #2231) — общедоступный JSON-фид всей доски talent-network a16z Speedrun. Закреплён по хосту speedrun-talent-network.com, только HTTPS, постраничная выборка с 0-индексацией и лимитом страниц, сквозная передача q/конфигурации по компании, fail-soft.
    • Cryptocurrency Jobs (cryptocurrencyjobs) — доска вакансий Web3 cryptocurrencyjobs.co, забираемая через её публичный RSS 2.0-фид (без авторизации). Двухпроходное декодирование XML-сущностей, только удалённые вакансии, работодатель извлекается из хвоста заголовка "… at <Компания>".
    • Реестр теперь поставляется с 72 источниками = 67 английских + 5 русских (ALL_ADAPTERS = 67 адаптеров англоязычных порталов).

Исправлено

  • echojobs — гибридные вакансии остаются отличимы от удалённых (зеркалит родительский #2258). Регистронезависимый маркер hybrid теперь даёт "<Город> · Hybrid" (или просто Hybrid, если города нет) и workplaceType: 'Hybrid', вместо схлопывания в Remote.
  • radancy — устаревшая разметка TalentBrew + транспорт JSON results-фрагмента (зеркалит родительский a3e6df9), под инжектируемым opts.fetchJson.

Примечания

  • Не портировано — CLI-специфичные функции родителя. Обширная CLI/mode-поверхность career-ops v1.24.0 остаётся вне web-ui, который является вьюером + тонким write-through, а не хостом режимов: таблицы соответствия/юрисдикции, телефонная книга контактов + vCard, транскрипт-дебриф интервью / определение платформы звонка, установка статуса в ledger, запись исхода, двухпроходный триаж, jd-similarity, версионированная схема артефакта CV заявки, детектирование Playwright-MCP в doctor и portals/fix-slugs.mjs. Изменения оркестрации скана, которые живут в родительском scan.mjs — Playwright-сканер Interamt.de, полный проход iCIMS в режиме reverse-ATS, фильтр допустимости страны для удалённых вакансий, троттлинг DNS-lookup, дедупликация StepStone rltr и нормализованная колонка компании в истории сканирований — не применяются: web-ui запускает сканеры EN/RU in-process и не шеллится в scan.mjs.
  • Уже покрыто. Фикс свёртки акцентов в role-matcher (#2209) был портирован в v1.127.0, так что здесь это no-op.

[1.129.1] — 2026-07-29

Исправлено

  • Доработки по AI-ревью портов web из v1.128/v1.129 (все адвайзори, исправлено в корне): порядок грейда в job-facets.js (явный модификатор теперь побеждает управленческое слово — Senior Engineering Manager → senior, было lead); fallback в states.mjs больше не пиннится (успешное чтение мемоизируется, fallback возвращается без кэша — родитель, временно недоступный на буте, перечитывается при следующем вызове) + console.warn при присутствующем, но битом файле; score-tone.js — строка без оценки нейтральна (muted), не красная; domainFromName() пропускает не-ASCII slug до /api/logo; +sanity-гард изоляции в tests/states.test.mjs. +4 теста → 2073.

[1.129.0] — 2026-07-29

Добавлено

  • Фасет «Грейд» + колонка «Свежесть» в #/scan — библиотека job-facets.js из v1.128.0 теперь вплетена в UI сканирования (раньше была только логика). Новый дропдаун Грейд раскладывает заголовок каждой вакансии на lead/staff/senior/mid/junior/intern (JobFacets.seniorityFromTitle) и автозаполняется тем, что реально есть в результатах (как фасет «Страна»); заголовки без слова-грейда всегда проходят. Сохраняется в сохранённых поисках, Сбросе и Применить. В таблице появляются колонка Грейд (бейдж) и zero-token колонка Свежесть (сегодня / Nдн, из JobFacets.daysSince). 12 i18n-ключей ×17, +3 теста → 2069.

[1.128.0] — 2026-07-29

Добавлено

  • Четыре решения, портированные из собственного веб-приложения родителя (../web/, Next.js) — переписаны на ванильном JS/ESM, без новых зависимостей: (1) server/lib/states.mjs читает templates/states.yml вживую как канонический словарь статусов трекера (с CI-fallback) — устраняет ручной ре-синк whitelist каждый релиз; POST сворачивает алиасы (испанские/legacy) в канонический ярлык, funnel в GET группирует по каноническому статусу; (2) логотипы компаний на ATS-хостованных строках через domainFromName() (~90 бренд→домен) перед буквой-аватаром; (3) score-tone.js — 4-уровневый тон оценки (≥4.2/3.8/3.0 + letter-fallback); (4) job-facets.js — фасеты seniority/source/days. +21 тест.

Примечания

  • Не портировано (только концепт): агентский слой действий родителя (actions/registry.ts + api/assistant/route.ts) — чертёж на случай, когда docs-fab вырастет из help-чата в копайлот. Новых источников нет (реестр 70), изменений i18n/help нет.

[1.127.0] — 2026-07-29

Добавлено

  • Три новых источника сканирования (паритет career-ops v1.23.0) — в реестре теперь 70 адаптеров (65 EN + 5 RU): Flowxtra (board-wide агрегатор без авторизации), VDAB (keyword-API фламандской службы занятости) и iCIMS (порталы careers-<tenant>.icims.com, отдельно от jibeapply). Плюс Cursor вернулся в ростер CLI (parent #2115): cli-detect теперь детектит cursor (10 инструментов), ростер восстановлен в help/README/config ×17.

Исправлено

  • agenticjobs переведён с HTML-скрейпинга на REST API (#2167); Greenhouse восстанавливает город из /offices, когда location.name — только модель работы (#2104); паритет role-matcher (#1933/#2164/#2009: префикс MTS, базовый токен product, свёртка акцентов, несогласие sub-baseline).

Примечания

  • Не портировано. Основная часть v1.23.0 — CLI/dashboard-поверхность, в которую web-ui не шеллится (batch-tailor, discover-ats, режимы NL/PT, темы PDF, Go-дашборд, updater/doctor); релейные скрипты не требуют правок. VERSION родителя → 1.23.0.

[1.126.1] — 2026-07-25

Исправлено

  • Две точки дрейфа ростера CLI, которые пропустил ресинк v1.126.0 — (1) интро вкладки API keys в #/config (config.providerModelNote, i18n ×17) перечисляло только 7 CLI — теперь Antigravity и Grok Build вставлены после OpenCode; (2) вторая строка сравнительной таблицы в help-гайде (×17) и собираемый в CI help сайта всё ещё содержали Inside Claude Code / Codex / Cursor / Gemini CLI — устаревший набор с Cursor — теперь полный ростер. Обе строки использовали разделители слэш/средняя точка, которые паттерны свипа v1.126.0 не покрывали. i18n-снапшот перегенерирован; сьют остаётся 1969.

[1.126.0] — 2026-07-25

Добавлено

  • Вкладка AI CLI tools теперь детектит все 8 первоклассных CLI career-ops — ростер #/config синхронизирован с родительским docs/SUPPORTED_CLIS.md: в server/lib/routes/cli-detect.mjs добавлены Grok Build CLI (grok) и Kimi CLI (kimi), а Antigravity теперь сначала ищет канонический бинарник agy. Read-only-скан 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 (legacy-обёртка). Help-бандлы сохраняют структуру 29 H2 / 105 H3.

[1.125.4] — 2026-07-23

Изменено

  • зависимости site (dependabot #151–#153) — sharp 0.34.5→0.35.3, svgo 4.0.1→4.0.2, fast-uri (dev) 3.1.3→3.1.4 в site/; сборка Astro зелёная, SPA/сервер не затронуты.

Примечания

  • Парити-свип родителя (career-ops 37d17ec..254764a, после v1.22.0) — портировать нечего: guard неверной строки в set-status (#2108) — только CLI (в web-ui строка трекера выбирается явно в UI, и ни один маршрут не вызывает set-status.mjs); Risk Summary в локализованных режимах (#2109) — файлы modes/<lang>/, которые web-ui не читает (только верхнеуровневые modes/*.md); проверка манифеста в update-system (#2111) — только апдейтер; остальное — доки родителя (турецкий README, SIGNATURES ×4, SCRIPTS.md, акценты es). VERSION родителя остаётся 1.22.0 — parentVersion без изменений.

[1.125.3] — 2026-07-23

Исправлено

  • LLM-промпты на датском и хинди отвечали по-английски (сообщено пользователем) — LOCALE_NAMES и все пять наборов SCAFFOLD_STRINGS в server/lib/prompts.mjs так и не были расширены для da и hi, поэтому resolveLocale() откатывался в en, и каждый AI-промпт — deep research (живой и ручной), режимы, оценка, интервью, нетворкинг, CV Studio — терял директиву # Output language в этих двух локалях. Теперь обе — полноправные: языковая директива + локализованная обвязка. Регрессионный гейт в tests/locale-scaffold.test.mjs теперь обходит канонический список из 17 локалей вместо захардкоженных 12, а новый структурный гейт роняет любой ключ обвязки, падающий в английский — локаль, пропустившая prompts.mjs, больше не выйдет (+12 тестов, всего 1969).

[1.125.2] — 2026-07-22

Исправлено

  • Deep research через Gemini: HTTP 502 (MALFORMED_FUNCTION_CALL) (#145, вклад @Alien10140) — живой промпт /api/deep велел модели «Use WebFetch / WebSearch» и сохранить бриф в файл, но у безинструментальных API-провайдеров нет канала инструментов; Gemini отвечал вызовом функции вместо текста, что проявлялось как пустой HTTP 502. buildDeepPrompt и bundleProjectContext получили флаг headless: живые запуски (Anthropic/Gemini/каскад фолбэков) получают промпт без инструментов, который пишет бриф из встроенного контекста, а copy-paste-промпт для Claude Code сохраняет инструкции по инструментам. +1 тест в tests/critical-fixes.test.mjs.

Изменено

  • Дефолтные модели Gemini обновлены с устаревшей gemini-2.0-flash (#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/ против …/Vectorworks/); адаптер ранее схлопывал настроенный URL до его origin, незаметно сканируя вакансии родительского бренда. Теперь эндпоинт сохраняет префикс бренда, отбрасывая только завершающий сегмент /search/ или /tile-search-results/, чтобы ничего никогда не задваивалось само на себя; тенанты с одним доменом остаются побайтово неизменными. Новый экспортируемый хелпер resolveTenantBase + 1 перенесённый тестовый блок в tests/sources-successfactors.test.mjs.

[1.125.0] — 2026-07-21

Добавлено

  • cvstart.org: раздел лендинга «Источники вакансий» — новый раздел между скриншотами и сравнением, который перечисляет все 67 источников сканирования в виде кликабельных чипов (62 англоязычные доски/ATS + 5 российских досок под отдельным подзаголовком), каждый из которых ведёт на публичный сайт источника. Список синхронизируется с живым реестром адаптеров при сборке (sync-assets.mjs → facts.sources), поэтому он никогда не может разойтись с приложением; курируемая карта ссылок в Sources.astro защищена новым тестом tests/site-sources.test.mjs. В навигации шапки появился якорь Sources; добавлено 4 новых ключа i18n сайта ×17. Также исправлен список inLanguage в JSON-LD лендинга, в котором всё ещё не хватало hi.

[1.124.0] — 2026-07-21

Добавлено

  • Пять источников сканирования (паритет с родительским career-ops v1.22.0, #1808/#1572/#2024/#2055) — Welcome to the Jungle (JSON API по всей доске вакансий), Agentic Engineering Jobs (доска вакансий по agentic/AI-инженерии), Jobvite (ATS без авторизации, на тенант), Gem (ATS на тенант) и Alibaba Group (JSON API карьерной страницы, паттерн Meituan/Tencent). Каждый источник — это закреплённая по хосту, CI-изолированная пара «источник + адаптер»; реестр теперь поставляется с 67 адаптерами (62 EN + 5 RU); фолбэк выпадающего списка Source на #/scan и его дрифт-гейт обновлены; пять новых наборов тестов tests/sources-{wttj,agenticjobs,jobvite,gem,alibaba}.test.mjs.

Исправлено

  • Arbeitsagentur: общенациональная удалённая работа определяется только при homeofficetyp равном VOLLSTAENDIG (родитель #1981) — запрос homeoffice=nv_true также возвращает гибридные вакансии, поэтому проверка удалённого формата теперь подтверждает каждое совпадение через эндпоинт деталей вакансии небольшими пакетами и при ошибке выборки закрывается безопасно (оставляет реальный город вакансии, чтобы фильтры по локации по-прежнему применялись).
  • SmartRecruiters: публичные URL вакансий формировались без /postings/ (родитель #2047) — ссылки теперь ведут на публичную страницу вакансии вместо 404 для тенантов, чей публичный сайт опускает этот сегмент.

Примечания

  • Родитель v1.22.0 также выпустил изменения на стороне CLI, в которые веб-интерфейс не заходит через shell или которые уже покрыты иначе: шаблон CV для zh-CN и типографика PDF, режим /expand, доработки кеширования промптов у провайдеров (Gemini/OpenAI/Ollama), пошаговая разбивка токенов (у веб-интерфейса свой счётчик использования), сериализация записи трекера через writer-lock (веб-интерфейс проводит записи через withFileLock с версии v1.21), флаги CLI visa_filter и абсолютной даты публикации для скана (у веб-интерфейса свой фильтр «Опубликовано за» по возрасту), а также посев дедупликации по увиденным источникам (сканер веб-интерфейса ведёт собственную дедупликацию истории сканирований).

[1.123.0] — 2026-07-17

Добавлено

  • Источник сканирования Oracle Recruiting Cloud (паритет с родительским career-ops v1.21.0, #1929) — REST API recruitingCEJobRequisitions карьерных сайтов Oracle Fusion/ORC без авторизации (JPMorgan Chase, Oracle, BNY Mellon, American Express, Honeywell и др.): хост закреплён по паттерну *.fa[.<region>][.ocs].oraclecloud.com, номер сайта определяется из careers_url каждой отслеживаемой компании, постраничная выборка по offset с жёстким лимитом числа страниц и WAF-совместимые «браузерные» заголовки. Реестр теперь поставляется с 62 адаптерами (57 EN + 5 RU); фолбэк выпадающего списка Source на #/scan и его дрифт-гейт обновлены; новый CI-изолированный набор tests/sources-oraclecloud.test.mjs.

Исправлено

  • Детектор повторных публикаций: базовые заголовки больше не смешиваются со «специализированными» вариантами-соседями (родитель #1922) — «Senior Analytics Engineer» больше не группируется с «Senior Analytics Engineer, People Analytics»: если токены одного заголовка являются строгим подмножеством токенов другого, а лишний токен — настоящая специализация (а не базовое слово), обе вакансии считаются отдельно публикуемыми позициями. Пометки о повторных публикациях («(Repost)», «relisted») теперь исключаются как метамусор (стоп-слова). +2 проверки в tests/detect-reposts.test.mjs.

Примечания

  • Родитель v1.21.0 также выпустил изменения на стороне CLI, в которые веб-интерфейс не заходит через shell или которые уже покрыты иначе: предупреждение о повторной подаче в ту же компанию (у веб-интерфейса своя логика кулдауна повторной подачи с v1.84.0), флаги --format/--report для сопроводительного письма, режимы промптов для интервью (red-flag / panel-intel / письмо о неявке), сохранение trust-сигналов сканирования и здоровья порталов (веб-интерфейс использует собственный in-process сканер с trust-validator и страницу здоровья порталов), а также расширения статистики/salary-gap (транслируются только для чтения, в fail-soft режиме).

[1.122.0] — 2026-07-16

Добавлено

  • Хинди (हिन्दी) — 17-й язык — полный словарь интерфейса (~1110 ключей), полное встроенное руководство справки (паритет 29 H2 / 105 H3), README.hi.md, новый CHANGELOG.hi.md (начинается с v1.122.0, по образцу de/it/tr), лендинг cvstart.org и страницы Methodology/License/Changelog/Help, переключатель языка (🇮🇳), автоопределение языка браузера и локализованный скриншот дашборда. Теперь каждый паритетный гейт «×16» проверяется как «×17»: паритет словаря i18n и снапшот, гейты H2/H3 справки, паритет CHANGELOG, check-i18n сайта и локальный прогон Playwright.

[1.121.0] — 2026-07-16

Добавлено

  • cvstart.org: страницы Methodology, License и Changelog — лендинг получил три новых раздела на всех 16 языках рядом с существующим блоком Compare: /methodology/ (шкала оценки из шести параметров 0.0–5.0, порог отклика 4.0 и правила «никогда не делает» — локализованное резюме career-ops.org/methodology), /license/ (канонический текст MIT со ссылкой на NOTICE.md) и /changelog/ (этот файл, отрисованный по локали из 16 переведённых CHANGELOG репозитория). Новый пункт «Методология» в шапке и ссылки в футере «Ресурсы»; sync-assets.mjs теперь синхронизирует CHANGELOG ×16 и LICENSE в сайт на этапе сборки, чтобы страницы никогда не расходились с репозиторием.
  • Ссылки на методологию по всей документации — README (все 16), канонический список §1 встроенного гида справки (все 16) и вики теперь ссылаются на career-ops.org/methodology (а также FAQ и глоссарий) наряду с существующими руководствами career-ops.org/docs.

Изменено

  • Обновлены баннер релиза и бейджи в 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-дашборде. Веб-интерфейс следует за ним: новая ссылка в футере боковой панели открывает страницу манифеста (новый ключ i18n footer.manifesto во всех 16 локалях), встроенный гид справки получил §29 «Манифест CareerOps» на всех 16 языках, README объясняет, что такое манифест и как его подписать, а футер лендинга cvstart.org тоже ссылается на него.

Примечания

  • Родитель v1.20.0 также исправил подавление известных навыков в целевом режиме upskill, заглушил dotenv, чтобы stdout scan --json оставался парсируемым, и исправил HTML-шаблон CV, чтобы заголовок роли не отрывался от своих пунктов — это поверхности на стороне CLI, в которые веб-интерфейс не заходит через shell; изменений кода веб-интерфейса не потребовалось.

[1.119.5] — 2026-07-13

Исправлено

  • Кнопка языка на лендинге больше не переносится — после появления флагов в v1.119.2 подпись переключателя в шапке (например «🇷🇺 Русский») могла разбиваться до трёх строк на узких десктопных ширинах; подпись переключателя и все пункты выпадающего списка теперь whitespace-nowrap — флаг + эндоним всегда в одну строку. Список языков в футере переведён с жёсткой двухколоночной сетки на переносимый ряд однострочных пунктов — «🇧🇷 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 (код, доки, переводы, лендинг, вики), что НЕ покрывает (ваши данные в рантайме, родительский проект, контент джоб-бордов, товарные знаки), таблицу сторонних компонентов (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, теперь существует: поддерживаемые версии, приватный процесс репортов (в репозитории включён private vulnerability reporting GitHub — вкладка Security → «Report a vulnerability»), модель угроз для localhost-приложения одного пользователя (в скоупе: XSS через враждебные вакансии / SSRF / path traversal / утечки секретов / ослабление CSP; вне скоупа: DoS собственного localhost и проблемы родительского проекта) и базовая линия харденинга для ревьюеров.

[1.119.2] — 2026-07-13

Добавлено

  • CONTRIBUTING.md — гид контрибьютора, на который лендинг и README ссылались всё это время, теперь существует: установка, карта проекта, жёсткие правила безопасности/no-build, уровни тестирования, walkthrough «двух реестров» для добавления скан-источника, контракт i18n ×16, конвенции коммитов/PR и процесс релиза.
  • Флаги языков на лендинге — переключатель языков cvstart.org, сетка языков в футере и баннер «читайте на своём языке» теперь показывают флаг каждой локали рядом с её эндонимом (тот же набор региональных индикаторов, что и в языковом <select> приложения; деградирует до букв региона там, где нет глифов флагов).
  • Правки футера лендинга — нерабочая ссылка Discussions (функция не включена в репозитории) теперь ведёт на вики проекта, а в футере указан автор: Sergei Emelianov (sergey-cv.com · LinkedIn).

[1.119.1] — 2026-07-13

Исправлено

  • Фильтр источников на #/scan догнал реестр — статический список FALLBACK_SOURCES за выпадающим списком Source (используется только когда 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 EN + 5 RU). +20 тестов (1844).
  • Блок контрибьюторов на лендинге — cvstart.org показывает аватары всех, кто внёс код (GitHub API /contributors на этапе сборки, боты отфильтрованы), локализовано на все 16 языков, со ссылкой на полный граф контрибьюторов.
  • Живой счётчик звёзд GitHub на лендинге — бейдж в шапке теперь обновляется на клиенте из GitHub API при каждом визите (снимок этапа сборки — как fallback), а еженедельная пересборка Pages по расписанию не даёт устареть снимку и списку контрибьюторов; API-вызовы в CI аутентифицированы токеном.

Исправлено

  • Запросы Workday CXS несут браузерные заголовки (родительский #1813) — тенанты за Cloudflare (наблюдалось вживую: geico) отвечают 500 на запросы без обычных UA/accept-language/origin/referer; фетчер теперь выводит origin и слаг сайта из самого CXS-URL. Запросы Glints получили тот же браузерный UA + origin/referer — оба из общей константы BROWSER_LIKE_USER_AGENT в http-json.mjs.

[1.118.4] — 2026-07-10

Исправлено

  • Скан hh.ru давал 0 вакансий с российского IP (ссылки на региональном поддомене) — с российского резидентного IP hh.ru редиректит поиск на региональный поддомен (sochi.hh.ru, spb.hh.ru, …) и отдаёт ссылки на вакансии на этом поддомене. Парсер искал ссылку заголовка по жёсткому хосту https://hh.ru/vacancy/ и не находил ни одной региональной — полностью рабочий скан молча записывал 0. Теперь принимается любой хост *.hh.ru (реклама adsrv.hh.ru/click?… по-прежнему отсекается — у неё нет пути /vacancy/<id>), а URL результата канонизируется в https://hh.ru/vacancy/<id>. Проверено вживую: 17 реальных вакансий парсятся со страницы sochi.hh.ru, где раньше было 0. +1 тест (1824).

[1.118.3] — 2026-07-10

Исправлено

  • hh.ru молча возвращал 0 вакансий (заглушка VPN-проверки) — hh.ru теперь отвечает 302-редиректом на заглушку /vpncheeck («VPN мешает работе сайта») сетям, которые считает VPN/прокси (датацентровые IP); заглушка отдаёт HTTP 200 без единой карточки вакансии, и скан сообщал 0 без какой-либо ошибки. Сканер теперь распознаёт редирект по финальному URL ответа, отключает hh.ru до конца прогона и пишет честную подсказку: трафик должен реально выходить через резидентный IP — системный VPN/прокси может оставаться включённым, даже когда переключатель в браузере выключен. +1 тест (1823).

[1.118.2] — 2026-07-10

Обслуживание

  • Доводка лендинга (#118) — site/README.md приведён к Astro 7 (security-апгрейд из #116), убран неиспользуемый импорт, добавлены 4 исполняемых гарда для билд-скриптов лендинга: гейт i18n-паритета доказуемо падает на сломанном словаре, а sync-assets никогда не пишет за пределы site/ — набор 1822. Разобраны два алерта CodeQL (один исправлен в коде, один задисмиссен как намеренное поведение билда).

[1.118.1] — 2026-07-10

Исправлено

  • Скан hh.ru из-за пределов России — hh.ru теперь отдаёт HTTP 451 (региональная юридическая блокировка) не-российским IP на публичных страницах поиска. Сканер обрабатывает 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/lifetime и GET /api/stats/salary-gap — shell-out с нулевой стоимостью токенов, мягкая деградация {available:false} без родительского проекта.
  • 28 новых i18n-ключей во всех 16 локалях; справка §14/§26 обновлена на всех языках.

Тесты

  • +38 юнит-тестов (три сьюта паритета провайдеров + роуты релея/статуса) — всего 1817.

[1.117.2] — 2026-07-06

Фикс пустого трекера для shell-out паритета. Родительские скрипты каденции/паттернов выходят с кодом 1 и структурированным {error}-JSON, когда в трекере ещё нет заявок; доска фоллоу-апов и вкладка «Паттерны отказов» показывали это как «script-error». Оба маршрута теперь передают это как здоровое пустое состояние (available:true, empty:true), и UI показывает честное «пока пусто». Проверено вживую на реальном родителе.

Новое: нет.

[1.117.1] — 2026-07-06

Донастройка v1.117.0 (разбор CodeQL). Три shell-out эндпоинта (GET /api/followup, POST /api/followup/seed, GET /api/stats/patterns) теперь несут общий per-IP лимитер (каждый запрос порождает дочерний процесс; на loopback — no-op). Извлечение текста по URL в «Добавить в CV» вычищает теги до неподвижной точки и затем удаляет все оставшиеся </> — доказуемо полная зачистка для текста LLM-промпта. Поведение на корректном вводе не изменилось.

Новое: нет.

[1.117.0] — 2026-07-06

Пакет паритета с родителем — шесть возможностей родительского career-ops теперь в UI. (1) Доска каденции фоллоу-апов: страница #/followup открывается срочностью по каждой заявке (🔴 срочно / 🟠 просрочено / 🟡 ожидание / 🔵 остыло) из родительского followup-cadence.mjs, плюс кнопка «Проставить даты фоллоу-апов» (followup-seed.mjs --backfill). (2) Паттерны отказов: четвёртая вкладка Статистики запускает analyze-patterns.mjs (только чтение) — распределение исходов, рекомендации и доля продвижения по каждому ATS-вендору. (3) Добавить в CV: карточка CV Studio превращает URL проекта/публикации или вставленный текст в ATS-пункты, основанные ТОЛЬКО на этом источнике (только предложения, без записей; загрузка URL защищена от SSRF). (4) 4 новых сканер-провайдера — beesite (бэкенд jobs.mercedes-benz.com), HigherEdJobs (RSS), JibeApply (iCIMS), softgarden — реестр теперь насчитывает 50 адаптеров (45 EN + 5 RU), все в выпадающем списке Scan. (5) Шаг предпроверки нокаут-вопросов в чек-листе Apply (виза/степень/зарплатные пороги — до заполнения формы). (6) Раннер reconcile (/api/run/reconcile → reconcile-pipeline.mjs). Shell-out-маршруты деградируют честно: без родительских скриптов UI показывает «недоступно».

  • Новый модуль маршрутов server/lib/routes/followup.mjs (31-й) + GET /api/stats/patterns + POST /api/cv-studio/add-entry + 8 файлов source/adapter + счётчики реестра 41→45 EN. Тесты: tests/sources-parity-v1117.test.mjs (6) + tests/parity-routes-v1117.test.mjs (7); сьют 1737 → 1750. 41 новый ключ i18n ×16. Справка §13/§17/§24/§26 расширена ×16.

Новое: GET /api/followup, POST /api/followup/seed, GET /api/stats/patterns, POST /api/cv-studio/add-entry, POST /api/run/reconcile.

[1.116.0] — 2026-07-06

Переработан счётчик расхода + первый сквозной тест виджетов. Счётчик расхода ИИ (v1.114.0) закреплён правильно: теперь он прижат к низу левой боковой панели (на всю ширину панели, с той же поверхностью) и резервирует внизу место, равное своей высоте, чтобы меню никогда не перекрывалось — навигация и подвал версии всегда прокручиваются свободно над ним. Он обновляется вживую (каждые 15 с, плюс при фокусе вкладки и смене маршрута), а каждая строка окна теперь показывает реальные <токены> · <оценка стоимости> (полосы масштабируются относительно 30-дневного окна) вместо всегда-100% «доли». Кроме того: устойчивый барьер typeof в импортёре CV закрывает в первопричине повторяющийся ложноположительный type-confusion CodeQL, а новый сквозной тест Playwright прогоняет оба постоянных виджета в реальном браузере.

  • public/js/lib/usage-hud.js + app.css, server/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 (иначе он перерисовал бы кольцо на заголовках маршрутов; урок v1.58.x).

  • Только CSS (public/css/app.css); без изменений разметки, i18n, маршрутов или CSP. Тесты: tests/design-polish-v1115.test.mjs (5). Проверено вживую через Playwright.

Новое: нет.

[1.114.0] — 2026-07-06

Счётчик использования и стоимости ИИ в боковой панели (левый нижний угол). Компактный раздел ИСПОЛЬЗОВАНИЕ теперь находится внизу боковой панели (фиксированная карточка в левом нижнем углу, если панели нет; в правом нижнем для RTL) на каждой странице. Он показывает использование токенов LLM по окнам 24ч / 7д / 30д — каждое как <токены> · <доля%> с зелёной полосой (доля от всего времени) — плюс подвал с оценкой стоимости за 24ч. Данные — доступный только для чтения свод GET /api/usage из data/llm-usage.jsonl (только локально), тот же источник, что и страница #/usage; стоимость оценочная, а запуски в ручном режиме бесплатны и не учитываются. Сворачивается — заголовок переключает, состояние сохраняется.

  • Новый клиентский виджет public/js/lib/usage-hud.js (window.UsageHud), загружается из index.html, монтируется в боковую панель над подвалом версии (запасной вариант — фиксированный угол). Безопасен для CSP; с учётом темы и зеркалом RTL. Без нового маршрута сервера. Тесты: tests/usage-hud.test.mjs (8). 3 новых ключа i18n ×16.

Новое: нет.

[1.113.0] — 2026-07-06

Плавающий помощник «Спросить справку» на каждой странице. Кнопка-робот с чатом и градиентом теперь плавает в правом нижнем углу (в левом нижнем для RTL) каждой страницы. Нажмите, чтобы открыть компактный чат, который отвечает на вопросы по использованию, опираясь ТОЛЬКО на встроенную справку на вашем языке — тот же эндпоинт, что и страница #/docs-assistant (POST /api/docs-assistant/ask), так что он никогда не читает ваше резюме, профиль или трекер. Вживую с LLM-ключом; без ключа → готовый к запуску промпт. В шапке — аватар-робот и статус онлайн; чипы подставляют частые вопросы; Escape или клик снаружи закрывает; на самой странице #/docs-assistant кнопка скрыта.

  • Новый клиентский виджет public/js/lib/docs-fab.js (window.DocsFab), монтируется глобально из index.html; безопасен для CSP; стили с учётом темы и зеркалом RTL в app.css. Без нового маршрута сервера — переиспользует эндпоинт справки. Тесты: tests/docs-fab.test.mjs (8). 6 новых ключей i18n ×16 (fab.* + docs.err). Справка §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) и дополнена закрытием CodeQL из v1.111 — так что он самодостаточен как единый регрессионный промпт для всей функциональности. Добавлен один тест покрытия для ветки слишком большой загрузки.

Новое: нет.

[1.111.0] — 2026-07-06

Безопасность — закрытие бэклога CodeQL. Три усиления эшелонированной защиты, которые закрывают оставшиеся замечания статического анализа в первопричине, а не через dismiss. stripDangerousMarkdown теперь экранирует < у любого усечённого открывающего опасного тега (полезная нагрузка, заканчивающаяся на <script/<iframe/…), так что в выводе доказуемо не остаётся живого опасного тега. Импорт CV читает размер загруженного буфера через явное приведение Number() — барьер против путаницы типов. Строки роли режимов теперь являются шаблонными строками, интерполируемыми через String.replace, а не хранимыми функциями, что полностью убирает вызов динамической диспетчеризации. Видимого для пользователя изменения поведения нет.

  • server/lib/security.mjs, server/lib/cv-import.mjs, server/lib/prompts.mjs. Тесты: tests/security-hardening-v1111.test.mjs (7) + обновлён тест-страж v1108. Без изменений i18n/справки/маршрутов.

Новое: нет.

[1.110.0] — 2026-07-06

Обновление документации и QA (все языки). Без изменений кода. Полнопроектный QA-промпт обновлён до v1.109.0 с новым §14 (v1.98→v1.109), а вечнозелёные промпты UX-аудита и design-export получили текущий набор экранов. Каждый абзац справки, добавленный в v1.100–v1.109, теперь переведён на все 16 языков.

Новое: нет.

[1.109.0] — 2026-07-06

Фильтр «Исключить» в Scan + обзор пайплайна (паритет с веб-версией). На #/scan поле Поиск теперь трактует запятые как ИЛИ («роли для поиска»), а новое поле Исключить скрывает строки, где компания/роль/локация содержат любое из слов через запятую (напр. 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). 4 новых ключа i18n ×16. Справка §7 + §8 расширены на месте.

Новое: нет.

[1.108.0] — 2026-07-06

Усиление безопасности (разбор CodeQL, раунд 2). Исправлены ещё три находки низкой серьёзности: сборщик промптов разрешает строку роли локали по собственному ключу + typeof === function, чтобы подделанная локаль не могла вызвать метод прототипа (unvalidated-dynamic-method-call); slug имени PDF-файла ограничен 200 символами до регулярки, чтобы вход из одних дефисов не откатывался (полиномиальный ReDoS); импорт документа приводит массивный filename (повторный заголовок) к строке (type-confusion). Без изменения поведения для корректного ввода.

  • server/lib/prompts.mjs, server/lib/routes/runners.mjs, server/lib/cv-import.mjs + tests/security-hardening-v1108.test.mjs (3). За v1.106–v1.108 бэклог статического анализа сократился со 167 до ~14: все действительно значимые для безопасности находки исправлены, остальное (защищённые/санированные ложные срабатывания + lint уровня note) отклонено с обоснованием.

Новое: нет.

[1.107.0] — 2026-07-06

Усиление санитайзера (эшелонированная защита от XSS в состоянии покоя). stripDangerousMarkdown — нейтрализует опасный HTML в сохранённом markdown резюме/вакансии, чтобы любой потребитель, минующий клиент с экранированием при рендере, оставался в безопасности — теперь выполняет удаление тегов до неподвижной точки (повторять до стабилизации), чтобы удаление, переформирующее полезную нагрузку (напр. <scr<script></script>ipt>), было поймано, совпадает с закрывающими тегами script/style и т. п. с мусором в конце (</script foo>) и удаляет незакрытый исполняемый открывающий тег (<script …>). Поведение для корректного markdown не меняется — удаляет только больше.

  • server/lib/security.mjs: цикл неподвижной точки (ограничен 8 проходами) + шаблоны закрывающих тегов [^>]*> + удаление незакрытого открывающего тега. +3 регрессионных случая в tests/cv-xss-bypasses.test.mjs. Авторитетная граница XSS остаётся экранированием на выводе (UI.md); это усиливает гарантию в покое и закрывает соответствующие находки CodeQL.

Новое: нет.

[1.106.0] — 2026-07-06

Усиление безопасности (разбор CodeQL). Исправлены три реальных (пусть и низкой серьёзности) находки из бэклога статического анализа: путь ошибки рендера маршрута теперь экранирует сообщение об ошибке до попадания в DOM (ошибка сервера может отразить пользовательский ввод, поэтому считается недоверенной — граница XSS), а записи свойств профиля/конфига отклоняют ключи __proto__ / constructor / prototype (защита от загрязнения прототипа на всякий случай — ключи берутся из фиксированных спецификаций полей, а не из сырого ввода). Большинство оставшихся предупреждений — ложные срабатывания на легитимных чтениях/записях сканера в data/* и на маршрутах, уже несущих собственный ограничитель; отклонены с обоснованием.

  • public/js/router.js экранирует err.message через UI.escapeHtml перед innerHTML; server/lib/routes/content.mjs и server/lib/routes/config.mjs защищают ключи прототипа. Без изменения поведения для корректного ввода. Тесты: tests/security-hardening-v1106.test.mjs (3). Новых ключей i18n нет.

Новое: нет.

[1.105.0] — 2026-07-06

Страница расхода и стоимости ИИ. Новая страница Расход ИИ (боковая панель, рядом со «Здоровьем») показывает, сколько токенов вы потратили на живые генерации ИИ — оценки, отчёты, чаты — с разбивкой по провайдерам за последние 24 часа, 7 дней, 30 дней и всё время, с оценкой стоимости в USD. Каждый живой вызов добавляет небольшую запись {provider, in, out} в data/llm-usage.jsonl (никуда ничего не отправляется); запуски без ключа (ручной режим) ничего не стоят и не записываются.

  • Новый модуль маршрута (30-й) server/lib/routes/usage.mjs — GET /api/usage (агрегаты только для чтения) + server/lib/llm-usage.mjs (recordUsage нормализует форматы usage у Anthropic/OpenAI/Gemini и добавляет best-effort; readUsage/aggregate агрегируют по окнам 24ч/7д/30д/всё × провайдер) + server/lib/llm-pricing.mjs (редактируемая таблица цен по провайдерам $/1M токенов — токены точны, доллары — приблизительные прайс-цены, которые можно исправить под тариф; не выставляются к оплате). Запись подключена в точках диспетчеризации (runActiveProvider + routes/llm.mjs).
  • Новое представление public/js/views/usage.js (#/usage, вкладки окон). Тесты: tests/usage-routes.test.mjs. 17 новых ключей i18n ×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. Логотип — это favicon компании, взятый с её собственного домена и проксируемый на сервере (GET /api/logo), поэтому ни один сторонний сервис логотипов не узнаёт, каких работодателей вы смотрите. Вакансии на общем портале (Greenhouse, Lever, Ashby, …) показывают цветной буквенный значок вместо иконки портала, и любой не загрузившийся логотип откатывается на тот же значок.

  • Новый модуль маршрута (29-й) server/lib/routes/logos.mjs — GET /api/logo?domain=. Он валидирует домен (без схемы/пути/loopback), берёт /favicon.ico через SSRF-безопасный safeGet (новый режим binary возвращает сырые байты + content-type; DNS-пиннинг, проверка редиректов и лимит размера не изменены), выполняет сниффинг сигнатуры изображения, чтобы никогда не отдать HTML-страницу ошибки как картинку, кэширует попадания и промахи в LRU в памяти и ничего не пишет на диск.
  • Новая клиентская библиотека public/js/lib/company-logo.js (window.CompanyLogo): по умолчанию выключена через флаг в localStorage; пропускает общие ATS-хосты в пользу детерминированного буквенного аватара; CSP-безопасный откат img.onerror. Тесты: tests/logo-routes.test.mjs. 5 новых ключей i18n ×16 (appear.*). Справка §2 расширена на месте.

Новое: server/lib/routes/logos.mjs; public/js/lib/company-logo.js.

[1.103.0] — 2026-07-06

Настройки: «Инструменты CLI для ИИ» — какие установлены. career-ops работает на Claude Code, но совместим с любым агентским CLI открытого стандарта skills. Новая вкладка Инструменты CLI для ИИ в Настройках (#/config) показывает, какие из них — Claude Code, Codex, Gemini CLI, OpenCode, GitHub Copilot CLI, Qwen, Antigravity — установлены на машине, где запущен сервер, и их пути. Это сканирование PATH только для чтения: проверяется лишь наличие каждого бинарника, и он никогда не запускается (без --version, без выполнения), ничего не пишется и данные пользователя не затрагиваются.

  • Новый модуль маршрута (28-й) server/lib/routes/cli-detect.mjs — GET /api/cli-detect. Определение резолвит путь бинарника из фиксированного списка из 7 записей по process.env.PATH (шимы .cmd/.exe/.bat в Windows; бит выполнения в POSIX); враждебный файл на PATH никогда не будет выполнен этим маршрутом.
  • Новая вкладка «Инструменты CLI для ИИ» в public/js/views/config.js (ленивая загрузка, диплинк через #/config?tab=cli). Тесты: tests/cli-detect-routes.test.mjs. 8 новых ключей i18n ×16 (cli.* + config.tabCli). Справка §2 расширена на месте.

Новое: server/lib/routes/cli-detect.mjs.

[1.102.0] — 2026-07-05

«Спросить справку» — чат с опорой на встроенную справку. Новая страница Спросить справку 💬 (боковая панель, под «Справкой»): введите вопрос вроде «Как сканировать порталы вакансий?» и получите ответ только из встроенной справки приложения на вашем языке — показывает, какие разделы использованы, и никогда не читает ваше резюме, профиль или поиск работы. Это о том, как пользоваться приложением, а не о вас. С ключом LLM отвечает вживую; без ключа выдаёт готовый промпт, уже заполненный нужными разделами справки.

  • Новый модуль маршрута (27-й) server/lib/routes/docs-assistant.mjs — POST /api/docs-assistant/ask. Поиск без зависимостей: справка на вашем языке разбивается на разделы ## и оценивается по совпадению ключевых слов с вопросом; лучшие включаются, и модель должна отвечать из них или сказать, что справка это не покрывает (без выдуманных функций/маршрутов). Общий каскад провайдеров, ручной откат, ограничение частоты, без записей, не читает данные пользователя.
  • Новое представление public/js/views/docs-assistant.js. Тесты: tests/docs-assistant-routes.test.mjs. 14 новых ключей i18n ×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 советует. Механика — выжимка из практики карьерного консультирования в общие правила: рекрутер читает за секунды, поэтому релевантное идёт наверх, заголовок совпадает с ролью вакансии, в результатах — конкретные цифры, а письмо остаётся коротким тизером с единственной «смычкой» «требование ↔ ваш подходящий факт». Основано только на вашем резюме, профиле и two-pager и ничего не выдумывает — без зашитых компаний, ролей или истории.

  • Новый эндпоинт POST /api/cv-studio/tailor (расширяет существующий модуль cv-studio — без 27-го модуля): buildTailorPrompt + общий гейт TAILOR_INSTRUCTIONS, на основе bundleProjectContext (резюме + профиль + two-pager), общий каскад провайдеров, ручной промпт без ключа, с ограничением частоты, без записей. Результат экспортируется в Markdown / PDF / DOCX через общую панель report-export.js.
  • Тесты: +3 в tests/cv-studio-routes.test.mjs. 10 новых ключей i18n ×16 (cvs.tailor*). Общий референс docs/prompts/resume-cover.md. Справка §24 расширена на месте.

Новое: docs/prompts/resume-cover.md.


career-ops-ui v1.267.1 · page 7/13 · mirror of the project changelog for cvstart.org