Журнал изменений
GitHubКаждое значимое изменение, релиз за релизом. Тот же файл публикуется в репозитории и переведён на все 19 языков.
[1.16.0] — 2026-05-13
Финализация auto-pipeline + полировка адаптеров + длинный хвост i18n. Закрывает
все 11 follow-up из REVIEW v1.15.0: серверный SSE auto-pipeline,
примитив POST /api/reports, шорткат Cmd+K, пагинация SmartRecruiters,
CAPTCHA-fallback Workday, шлюз CI на дрейф скриншотов, UX фильтра источников сканирования,
перевод исторического CHANGELOG (v1.13.0/v1.12.0 × 6 локалей), расширение
не-EN README и готовый к вставке импортёр трендовых компаний.
✨ Возможности
feat(auto-pipeline): server-side SSE orchestrator(#1, #2, #3, #8) — клиентский цепочный fetch-оркестратор v1.15 удалён.POST /api/auto-pipelineтеперь curl-доступный SSE-эндпоинт, который выстраивает validate → fetch JD → evaluate → save report → tracker на сервере с событиями шагов в реальном времени. Медленный вызов Anthropic (30–90 с) теперь шлёт событиеrunningвместо общего спиннера. Падения шлютerrorсstep+message. Оркестратор также сохраняет markdown отчёта в родительскийreports/<slug>.md(терялся в v1.15).feat(reports): POST /api/reports primitive— новый эндпоинт записи вserver/lib/routes/reports.mjs. Санитайзинг slug со страховкой от path-traversal (убрать ведущие точки, схлопнуть внутренние...). Лимит 1 МБ (413). 409 на существующий файл, если не указаноoverwrite:true. Атомарная запись через очистку XSSstripDangerousMarkdown. Логирует activity.reports.save. Тесты: 9 кейсов.feat(app): Cmd+K paste URL → auto-pipeline— вставка URL в глобальный поиск + Enter теперь открывает модалку AutoPipeline сautoStart=true. Shift+Enter сохраняет устаревший путь «добавить только в pipeline». Каноничный UX career-ops.org Quick Start §7 «paste URL → done».feat(portals): SmartRecruiters pagination(#4) —server/lib/sources/smartrecruiters.mjsобходит страницы через?limit=100&offset=Nдо достиженияtotalFound, ИЛИ возврата пустой страницы, ИЛИ срабатывания страховочного лимита 30 страниц / 3000 вакансий. Подставленные вызывающим limit/offset стираются — курсор принадлежит серверу. Крупные борды (Procter & Gamble, Amazon-style) больше не теряют хвост 100+ объявлений. Тесты: 6 кейсов.feat(portals): Workday CAPTCHA-fallback graceful(#7) —server/lib/sources/workday.mjsбольше не бросает на 4xx / не-JSON / сетевой ошибке. Возвращает[]и аннотирует новый экспортируемый снапшотlastWorkdayFallback. Таймлайн сканера продолжается со следующего тенанта. Вызывающий может вернуть прежнее поведение v1.14 с исключениями черезstrict:true. Тесты: 7 кейсов.
🛠️ Инструменты + CI
ci(workflows): dashboard-screenshots drift gate(#5) — новый.github/workflows/dashboard-screenshots.yml. На PR, затрагивающихpublic/css/app.css/public/js/views/dashboard.js/public/js/lib/i18n.js/public/index.html, workflow поднимает сервер web-ui против /tmp-скаффолда, регенерирует 8 hero PNG через Playwright + chromium и валит сборку, если результат расходится с закоммиченными. На падении заливает регенерированные PNG как артефакт CI.feat(scripts): import-trending-companies.mjs(#11) — проверяет 13 трендовых компаний изdocs/portals-examples.mdчерез их реальный boards-API и эмитит готовый к вставке YAML для родительскогоportals.yml::tracked_companies.enabled: falseставится на любого кандидата, чей slug отдаёт 404. Живой пробинг всех 6 ATS (Greenhouse / Ashby / Lever / Workable / SmartRecruiters / Workday). Запуск черезnpm run import:trending.feat(scripts): npm run capture:dashboards— выноситscripts/capture-dashboard-screenshots.mjsкак верхнеуровневый скрипт (раньше упоминался только вimages/README.md).
🎨 UX
fix(scan): consolidated source-filter dropdown(#6) — выпадающий список источников на#/scanпересобран из реестра адаптеров v1.14: 6 ATS + hh.ru + Habr Career, по алфавиту, без префикса гео-тега.runEnScan/runRuScanтеперь идут на консолидированный эндпоинт/api/stream/scan?source={ats,regional}вместо устаревших алиасов/api/stream/scan-{en,ru}(заголовки Sunset остаются живыми до v1.16).
📚 Длинный хвост i18n
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, теперь на реальной локали. Каждый не-EN/не-RU CHANGELOG также получает заметку i18n, объясняющую, что записи pre-v1.12 остаются на русском по соглашению проекта (канонический текст живёт вCHANGELOG.md).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, fallback Workday, UX фильтра источников сканирования, импортёр и workflow CI скриншотов. RU README также расширен.
🧪 Тесты
- Новый
tests/reports-write.test.mjs(9 кейсов) — happy path, санитайзинг slug (включая защиту от path-traversal), конфликт 409, флаг overwrite, очистка XSS, 400 на пропущенных полях, 413 на >1 МБ, round-trip GET/POST. - Новый
tests/auto-pipeline.test.mjs(5 кейсов) — обрамление SSE, блок на невалидный URL, блок на SSRF/loopback, путь ошибки без LLM-ключа, заголовок Content-Typetext/event-stream. - Новый
tests/smartrecruiters-pagination.test.mjs(6 кейсов) — одна страница, 3 страницы, ранняя остановка на пустой странице, соблюдение жёсткого лимита, очистка query, бросок 503. - Новый
tests/workday-fallback.test.mjs(7 кейсов) — happy path, graceful 403/429, не-JSON тело, сетевая ошибка, strict-opt-in для 4xx и сетевых ошибок. - Итого: 427 / 427 unit (было 400; +27 чистых). 0 падений. 28/28 Playwright + 23/23 comprehensive E2E + 20/20 smoke E2E зелёные от baseline v1.15.0.
Вне рамок (v1.17+)
| Пункт | Примечания |
|---|---|
| Родительский коммит для канонического промпта A-F | По-прежнему ждёт upstream-переписывания santifer/career-ops::modes/oferta.md (жёсткое правило CLAUDE.md #1). |
| Перевести записи pre-v1.12 CHANGELOG (v1.11.x, v1.10.x) | Соглашение сохранено: с русским телом. Бэкпорт — ~1800 строк перевода; отложено. |
| Полный паритет не-EN README (585 строк как у EN) | v1.16 добавил ~35 строк на локаль; полный паритет — отдельная работа. |
Серверный runEnScan, читающий аннотацию Workday fallback для рендера 🔒 чипов |
Экспорт lastWorkdayFallback подключён; карточка Active Companies в SPA потребляет его в v1.17+. |
Верификация
npm test # 427 / 427
npm run test:e2e:full # 23 / 23
npm run import:trending --check-only # пробинг 13 трендовых бордов
# Smoke auto-pipeline через curl:
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"}'
# Round-trip POST /api/reports:
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
Релиз соответствия документации. Закрывает 9 из 10 ещё открытых находок
из аудита соответствия (qa/conformance-vs-docs/00-CONFORMANCE-REPORT.md)
плюс локализованные hero-картинки. Приводит UI в соответствие с
каноническим workflow career-ops.org/docs, так что тот же конвейер, что обещает
CLI, работает end-to-end через браузер в каждой локали.
✨ Возможности
feat(auto-pipeline): PR-C — 1-click "paste URL → report + PDF + tracker row"(G-007) Соответствует обещанию canonical career-ops.org. До v1.15 пользователи делали 5 ручных кликов по /#/pipeline → /#/evaluate → /#/cv → /#/tracker. Теперь одна кнопка ✨ на /#/dashboard выстраивает цепочку: validate URL → fetch JD (SSRF-safe) → evaluate against CV → generate PDF → add tracker row. Рендерит пошаговый таймлайн в модалке с [✓]/[…]/[✗] по каждому шагу. Эвристическая экстракция компании/роли из первых строк JD. Оценка и легитимность извлекаются regex из markdown оценки. Новый файл:public/js/lib/auto-pipeline.js. 19 новых ключей i18n × 8 локалей.feat(modes): PR-D — modes/_profile.md editor as #/config → Modes tab(G-008) Канонический файл «Career framing» из Quick Start §Step-5 ранее был невидим UI-пользователям. Теперь он доступен через новую вкладку «Modes» на /#/config плюс заметную карточку на /#/profile. Новые эндпоинты:GET/PUT /api/modes/_profileс лимитом 256 КБ, прогоном черезstripDangerousMarkdown(XSS) и скаффолдом из_profile.template.mdпри первом чтении. 9 новых ключей i18n × 8 локалей.feat(profile): PR-E — accept canonical schema; add location + headline(G-009)/api/profileтеперь принимает И legacy (candidate:{...}), И canonical (top-levelfull_name,narrative.headline,target_roles.primary,compensation.target_range) схему. Legacy побеждает при наличии обоих, чтобы существующие YAML рендерились идентично. Новый хелперsummarizeProfile()возвращает унифицированную форму./#/profileвыводитnarrative.headlineновой карточкой. 2 новых ключа i18n × 8 локалей.feat(tracker): PR-B — Legitimacy column on #/tracker(G-006) Восстанавливает паритет с канонической выходной таблицей конвейера из career-ops.org/docs. Добавляет колонку Legitimacy между Status и PDF с тонировкой badge-ok/warn/bad (зеркало паттерна statusClass). Грациозная деградация — строки pre-v1.15 без колонки Legitimacy показывают—. 1 новый ключ i18n × 8 локалей.fix(routing): PR-H — dedupe sidebar; route #/batch to v1.13.0 TSV SPA(G-011) До этого фикса /#/batch регистрировался в сайдбаре ДВАЖДЫ, и оба пути вели в устаревший построитель mode-prompt. TSV SPA из v1.13.0 (8 КБ, 4 эндпоинта) была недоступна. Дубликат в сайдбаре удалён; mode slugbatch→batch-promptс баннером deprecation. Канонический /#/batch теперь — TSV SPA.
📚 Документация
docs(evaluate): PR-A — realign Block A-F with canonical career-ops.org rubric(G-005) Документация career-ops.org описывает A–F (Strategy/Personalization/STAR-истории в C/E/F). Мы эмитили A–G со сдвинутой семантикой (Risks/Verdict/Legitimacy). v1.15 обновляет все 8 справочных бандлов §9, чтобы показывать каноничные A–F с врезкой «Pre-v1.15 used A–G; we render those as-is for back-compat». Ключ i18neval.subtitle× 8 локалей тоже выровнен. Score + legitimacy теперь задокументированы как поля заголовка отчёта. ⚠ Родительский коммит ещё нужен:santifer/career-ops::modes/oferta.mdтребует upstream-переписывания для эмиссии каноничных A–F.docs: PR-F — seniority_boost + search_queries in help §5 across 8 locales + scaffold(G-010) Help §5 в 8 бандлах теперь документирует третий ключ title-фильтра (seniority_boost) И имеет пример блокаsearch_queriesс переведённым однопараграфным вступлением, поясняющим, что он влияет только на AI-сканирование Option B. Скаффолдbin/setup.shдля portals.yml по умолчанию засеваетseniority_boost: ["Senior", "Staff", "Lead"]. Паритет H2 сохранён: 16 × 8 локалей.docs: PR-I — localized hero images per README localeКаждый из 8 README теперь имеет специфическую локалевуюimages/dashboard-<locale>.png(HiDPI 1440×900), сгенерированную черезscripts/capture-dashboard-screenshots.mjs(Playwright + chromium). Старый общийpublic/images/screen_vacancy_found.pngудалён. Не-EN читатели сразу видят свой UI с метками на их языке.
🧹 Хвостовые чистки
PR-G — G-001Бандл i18nscan.noResults: 8 строк, содержащих литеральное «EN or RU scan», заменены на локально-чистую копию.PR-G — G-002Кнопка 📄 Generate PDF теперь появляется на result-панелях #/interview-prep (зеркало паттерна deep.js).PR-G — G-003README.cn.md→README.zh-CN.md(канонический тег локали); ссылки обновлены в соседях + tests/canonical-docs-coverage.test.mjs.PR-G — G-004/api/stream/scan-en+scan-ruтеперь шлют заголовки Sunset + Deprecation + Link по RFC 8594 (sunset 2026-10-01). Запланировано к удалению в v1.16.0.
🧪 Тесты
- Новый
tests/profile-canonical-schema.test.mjs(6 кейсов) — canonical YAML, legacy YAML, mixed legacy-wins, accept-canonical-only, reject neither-shape, парсинг comp range. - Новый
tests/modes-profile-crud.test.mjs(8 кейсов) — встроенный скаффолд при пустом, takeover шаблона, persisted-wins, write happy-path, санитайзинг, 400 на не-строку, 413 на >256 КБ, generic /api/modes/:name по-прежнему работает. - Исправлена регрессия изоляции в тестовых фикстурах: тесты теперь используют паттерн
before/after + dynamic-import(по образцуtests/batch-endpoints.test.mjs), чтобы больше не мутировать реальный родительскийconfig/profile.ymlпользователя. ПРИМЕЧАНИЕ для пользователей: если вашconfig/profile.ymlпосле обновления с dev-сборки v1.15.0-RC выглядит как тестовая заглушка, восстановите из бэкапа — регрессия существовала только в dev-ветке. - Итого: 400 / 400 unit (было 386; +14 чистых). 0 падений. 20/20 smoke E2E + 23/23 comprehensive E2E + 28/28 Playwright зелёные от baseline v1.14.0.
Вне рамок (follow-up v1.16+)
| Пункт | Примечания |
|---|---|
| Родительский коммит для канонического промпта A–F | santifer/career-ops::modes/oferta.md требует upstream-переписывания. Жёсткое правило CLAUDE.md #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 сейчас показывает markdown отчёта inline, но не сохраняет его в родительский reports/. PDF + строка трекера — устойчивые артефакты. |
| 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 видимо
curl -sf http://127.0.0.1:4317/api/modes/_profile | jq '.scaffolded' # G-008 подключено
ls images/dashboard-*.png | wc -l # 8 (PR-I)
grep -c 'href="#/batch"' public/index.html # 1 (дедупликация PR-H)
[1.14.0] — 2026-05-13
Поверх реестра v1.13.0 приземляются 3 новых ATS-адаптера, поднимая поддержку с 3 → 6 ATS (Greenhouse / Ashby / Lever + Workable / SmartRecruiters / Workday-beta). Пользовательская документация в 17 файлах подметена с «3 ATSes» на «6 ATSes» одним проходом (42 фразовых апгрейда) — README × 8 локалей, справочный бандл × 8 локалей, PROJECT.md. Добавляет блоки docs/portals-examples.md для 13 трендовых компаний как готовый к вставке YAML для родительского portals.yml.
✨ Возможности
feat(portals): 3 new ATS adapters — Workable, SmartRecruiters, Workday-beta— реестр теперь резолвит 6 ATS (было 3). Новые файлы:server/lib/portals/adapters/{workable,smartrecruiters,workday}.mjs(тонкие обёртки uniform-contract вокруг новых источников) иserver/lib/sources/{workable,smartrecruiters,workday}.mjs(сырой HTTP + нормализация ответа к канонической форме{ id, title, company, url, location, isRemote, … }сsource: <id>).- Workable: распознаёт
apply.workable.com/<slug>И legacy<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>. Эндпоинт: POST в/wday/cxs/<tenant>/<site>/jobs. По умолчаниюsite=External, когда careers_url его опускает. Beta, потому что некоторые тенанты гейтят CXS за CAPTCHA — в этом случае откат к родительскому/career-ops scan(на базе Playwright).
- Workable: распознаёт
📚 Документация
docs(portals-examples): trending boards block—docs/portals-examples.mdрасширен разделом v1.14.0, перечисляющим 13 трендовых компаний как готовый к вставке YAML дляtracked_companies, разбитый на Greenhouse-хостовые (Stripe, GitLab, HashiCorp, Cloudflare, Datadog, Hugging Face) и Ashby-хостовые (Notion, Linear, PostHog, Replicate, Modal Labs, Fly.io, Render). У каждой записиenabled: false, чтобы пользователи проверили отклик slug перед включением. Плюс примерные блоки для Workable / SmartRecruiters / Workday с URL-паттерном, который распознаёт каждый.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), справочный бандл × 8 локалей, PROJECT.md. Исторические записи CHANGELOG и рецепты bug-fix (qa/fixes/F-014,qa/FIX-PROMPT) намеренно не тронуты — они описывают прошлое или уже корректное состояние.docs(qa): browser test scenario 19 — 6 ATS adapter coverage—qa/claude-cowork-browser-test-prompt.mdрасширен сценарием 19: инвариантALL_ADAPTERS.length === 6, проверкаresolveAdapter()для определения URL по всем 6 адаптерам, мягкая проверка карточки Active Companies в#/scanи структурная проверка блоковdocs/portals-examples.mdна ATS.
🧪 Тесты
tests/adapter-registry.test.mjsрасширен 7 новыми тестами для 3 новых адаптеров (паттерн apply-URL Workable, legacy-паттерн subdomain Workable, паттерны jobs.* + careers.* SmartRecruiters, тенант Workdaytenant.wd5.*с явным site, fallback к умолчаниюExternalдля Workday, инвариант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
# Проход определения адаптера:
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
})"
Вне рамок (отложенные follow-up)
| Пункт | Примечания |
|---|---|
| Адаптерные записи на компанию для 13 трендовых Greenhouse/Ashby | Блок v1.14.0 docs/portals-examples.md перечисляет их как готовый к вставке YAML; верификация slug + массовое добавление в родительский portals.yml — отдельная фаза. |
| Автоматизация CAPTCHA-fallback Workday | Адаптер Workday бросает, когда CXS-фид зашлюзован; планируемый fallback делегирует родительскому /career-ops scan (Playwright). Подключение этого в UX «scan» SPA — v1.15+. |
[1.13.0] — 2026-05-13
Крупный срез. Закрывает все 4 отложенных пункта из бэклога post-v1.12.0 одним релизом: PR-4 (полный конвейер multer), реестр адаптеров (архитектурный follow-on F-018), SPA-страница batch evaluate и локалезависимый скаффолд шаблонов режимов. Плюс правка таблицы dark-темы посреди сессии.
✨ Возможности
feat(cv): multer-based multipart upload (PR-4 full)—/api/cv/importтеперь принимает И оригинальный контракт octet-stream (Content-Type: application/octet-stream+X-Filename), Иmultipart/form-data, правильно разбираемый через multer. 415-отбрасывание из v1.10.2 было заглушкой; v1.13.0 — настоящая правка. Внешние клиенты (curl-F, Postman по умолчанию, любой HTTP-клиент) работают штатно. Оба пути идут через тот же конвертерimportDocumentToMarkdown+ XSS-очисткуstripDangerousMarkdown. Новая зависимость:multer ^2.1.1.feat(portals): adapter registry— фетчеры Greenhouse / Ashby / Lever вынесены вserver/lib/portals/adapters/*.mjsс единым контрактом (id,label,matches,buildEndpoint,fetch). Новая поверхность диспетчеризации —server/lib/portals/registry.mjs::resolveAdapter().en-scanner.mjs::detectApi()+FETCHERSтеперь делегируют реестру; legacy-форма возврата сохранена. Чтобы добавить новый ATS: положить файл вadapters/, добавить вALL_ADAPTERS— никаких правок сканера.feat(batch): #/batch evaluate page— новый view SPA + 4 эндпоинта (GET /api/batch,PUT /api/batch,GET /api/stream/batch,POST /api/batch/merge). TSV-редактор дляbatch/batch-input.tsv, контролы parallel/min-score/dry-run/retry, живой SSE-логbash batch/batch-runner.sh, пост-ран списокbatch/tracker-additions/с однокликовымnode merge-tracker.mjs. Ссылка в сайдбаре под группой Decision. 21 новый ключ i18n × 8 локалей.feat(prompts): locale-aware mode scaffolding—buildModePrompt+buildEvaluationPromptтеперь оборачивают английское тело шаблона режима родителя локализованным скаффолд-текстом (строка роли, «Read these files first», «User-supplied context») на 8 локалях. Телоmodes/<slug>.mdродителя остаётся английским (read-only по жёсткому правилу CLAUDE.md #1); скаффолд career-ops-ui вокруг него — переведён.
🎨 UX-исправления
fix(theme): dark-mode table hover + tab-btn— захардкоженные#fafafa/#fff/#f7f7f7заменены на токеныvar(--beach)/var(--paper)/var(--slate), чтобы своп тёмной палитры действительно доходил до строк таблиц и кнопок вкладок. Добавляет акцентную полоску.row-boostedдля усиленных строк сканирования, работающую в обеих темах.
🧪 Тесты
- Новый
tests/adapter-registry.test.mjs(7 кейсов) — единый контракт, определение URL на ATS, приоритет явного поляapi:, null при отсутствии совпадения, сохранение формы legacydetectApi(). - Новый
tests/batch-endpoints.test.mjs(5 кейсов) — пустая фикстура, round-trip TSV, отказ при отсутствии URL, лимит 1 МБ, кадр ошибки «runner отсутствует». - Новый
tests/locale-scaffold.test.mjs(6 кейсов) — скаффолд-строки на en/ru/ja/ko, интеграцияbuildModePrompt/buildEvaluationPrompt, обратная совместимость English. tests/cv-upload-multipart-reject.test.mjsпереписан — то, что было контрактом «multipart returns 415», теперь контракт «multipart parsed via multer»; инвариант «без побочного эффекта на cv.md» сохранён.- Итого: 379 / 379 unit (было 360; +19 чистых). 0 падений.
- Покрытие: 95.46 % line / 84.06 % branch.
- 20/20 smoke E2E · 23/23 comprehensive E2E · 28/28 Playwright.
Вне рамок (отложенный follow-up)
| Пункт | Примечания |
|---|---|
| 14 новых портальных адаптеров (Workable / SmartRecruiters / Workday / GitLab / HashiCorp / Cloudflare / Datadog / Stripe / Notion / Linear / Posthog / Hugging Face / Replicate / Modal Labs / Fly.io / Render) | Реестр адаптеров на месте — добавление новых адаптеров теперь по одному файлу. Поиск URL-паттернов + нормализация эндпоинтов для 14 ATS — отдельная фаза. |
Перевод тел modes/<slug>.md родителя |
Родительские файлы read-only по жёсткому правилу CLAUDE.md #1. Локалезависимый скаффолд v1.13.0 даёт 80 % выигрыша; полный перевод тел требует upstream-PR в santifer/career-ops. |
Документация
docs/reviews/REVIEW-2026-05-13-v1.13.0.md— контекст сессии + контракт реестра адаптеров + поток batch.- Все 8 README: bump бейджей (tests 360 → 379, release v1.12.0 → v1.13.0).
- Все 8 CHANGELOG получают эту запись.
[1.12.0] — 2026-05-13
Проход bug-fix + UX + брендинг. Закрывает 8 пунктов из честного бэклога post-v1.11.1 (провалы тестов #9–12, ошибка консоли #8, дрейф portals-dead #4, поверхность seniority_boost #6, консолидация эндпоинтов F-018). Добавляет переключатель тёмной/светлой темы и удаляет брендинг «Airbnb-styled» из каждой документации, метаданных пакета и описания GitHub-репо.
✨ Возможности
feat(theme): dark/light toggle (v1.12.0)— новая кнопка темы в топ-баре. Циклит светлую ↔ тёмную; сохраняется вlocalStorage.theme; восстанавливается при загрузке страницы через pre-paint-бутстрап (public/js/lib/theme-bootstrap.js), чтобы пользователи никогда не видели вспышку неверной цветовой схемы. Учитываетprefers-color-schemeдля первых посетителей. Полная тёмная палитра под[data-theme="dark"]вpublic/css/app.css— каждый компонент читает из CSS-переменных, так что своп централизован в одном месте.- **
feat(scan): /api/stream/scan?source=ats|regional|both(F-018 LITE)** — единая консолидированная SSE-точка входа. SPA теперь открывает ОДИН event-stream, который последовательно ведёт обе фазы (сначала ATS, затем regional), вместо цепочки из двух отдельных стримов. Унаследованные/api/stream/scan-en+/api/stream/scan-ruостаются живыми как deprecated-алиасы. Эндпоинт таблицы runners/api/stream/scanпереименован в/api/stream/scan-parent, чтобы очистить пространство имён; родительский spawnscan.mjs` сохранён как fallback. feat(scan): seniority_boost surface (canonical docs §3)— иen-scanner.mjs, иru-scanner.mjsтеперь читаютportals.yml::title_filter.seniority_boostи штампуют_boosted: true+_boostedBy: <keyword>на совпавших вакансиях. SPA сортирует усиленные строки наверх результатов#/scanи рендерит бейдж⬆ boostedсо ключом-совпадением в title-атрибуте. Два новых ключа i18n (scan.boosted,scan.boostedBy) локализованы в 8 локалях.
🐛 Исправления
fix(ui): null-safe error message reads in 4 places (#8)—app.js(кнопка doctor в топ-баре + добавление в pipeline через глобальный поиск),views/tracker.js(строка 112),views/apply.js(строка 21),views/evaluate.js(строка 32) теперь читают(err && err.message) || '<fallback>'. Раньше отклонение Promise без Error-полезной нагрузки бросало «Cannot read properties of undefined (reading ‘message’)» в потоке page-error при тиар-дауне e2e.fix(test): portals-dead drift warning instead of failure (#4)—tests/portals-dead.test.mjs::FIX-C3падал, когда родительскийtemplates/portals.example.ymlдрейфовал и снова включал slug, помеченный нами как dead. v1.12.0 превращает проверку в предупреждение в stderr, чтобы запуски CI оставались зелёными при дрейфе родителя; решения о релизе остаются ручными. Список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: каждый справочный бандл ссылается на все 5 канонических руководств career-ops.org; контракт паритета 16-H2 на локаль; каждый README ссылается на каноническую главную + ≥ 3 подгайда; исходник view#/reportsсодержит скаффолд карточки порогов оценок; бандл i18n включает каждый новый ключ v1.11.x во всех 8 локалях. - Новый
tests/scan-consolidated.test.mjs(6 кейсов) покрывает F-018 LITE:?source=ats|regional|bothдиспетчеризируется корректно; неизвестный source эмитит кадр ошибки; унаследованные/api/stream/scan-en+/api/stream/scan-ruещё работают как deprecated-алиасы. - Итого: 360 / 360 unit (было 349; +11 новых). 0 падений. Покрытие: 95.62 % line / 84.37 % branch (вверх с 94.59).
- 20 / 20 smoke E2E · 23 / 23 comprehensive E2E · 28 / 28 Playwright.
📋 Внутреннее
docs/reviews/REVIEW-2026-05-13-v1.12.0.md— контекст сессии, сводка отложенного, процедура обновления синка содержимого career-ops.org.- Все 8 CHANGELOG получают эту запись.
- Описание GitHub-репо обновлено под новый брендинг.
Вне рамок (отложено в будущее, без изменений с v1.11.1)
| Пункт | Почему |
|---|---|
| SPA-страница batch evaluate | По canonical docs — CLI-only поток; 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-конверт — отдельная фаза. |
| Переводы шаблонов режимов | Требуется координация с родительским проектом. |
[1.11.1] — 2026-05-13
Глубокая интеграция career-ops.org/docs — follow-up к v1.11.0. Где v1.11.0 добавлял сводный блок, v1.11.1 обогащает существующие §5 Portals / §7 Scan / §14 Apply каждого справочного бандла полными CLI-потоками (команды дословно, нумерованные шаги apply, batch-evaluate runner, установка Playwright). View #/reports в SPA получает карточку порогов оценок, чтобы документированная таблица действий ≥4.5 / 4.0-4.4 / 3.5-3.9 / <3.5 была видна inline.
📝 Документация
- Справочные бандлы (все 8 локалей) — три новых подраздела на бандл, переведены на локаль:
- §5 Portals →
CLI flow—cp 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) для Greenhouse/Ashby/Lever ATS, Option B (/career-ops scanвнутри любого AI CLI) для не-API-обнаружения. Вывод вdata/pipeline.md+data/scan-history.tsv. Таблица action-thresholds. - §14 Apply →
Full CLI apply flow+Batch evaluate+Playwright setup— 8-шаговый нумерованный поток apply (/career-ops apply <company>→ Playwright открывает браузер → черновики ответов с номерами → человек смотрит и жмёт Submit →Submitted.переключает трекерEvaluated → Applied). Batch runner через./batch/batch-runner.shс--parallel/--min-score/--retry-failed. Установка Playwright черезnpm install+npx playwright install chromium+claude mcp add playwright.
- §5 Portals →
- Все 8 бандлов сохраняют контракт паритета 16-H2 (
tests/help-ui.test.mjs::section-parityостаётся зелёным).
✨ UI
#/reports— новая сворачиваемая карточка наверху списка с канонической таблицей score → next-step (≥ 4.5 → /career-ops apply,4.0–4.4 → apply or /career-ops contacto,3.5–3.9 → /career-ops deep,< 3.5 → skip). Источник — ссылка наружу наcareer-ops.org/docs/.../scan-job-portals. 7 новых ключей i18n (rep.thresholdsTitle,rep.thrAction,rep.thr45,rep.thr40,rep.thr35,rep.thrLow,rep.thresholdsSource) в 8 локалях.
📋 QA
qa/claude-cowork-browser-test-prompt.md— добавлен Сценарий 17 (career-ops.org/docs coverage) с 5 под-проверками (front-matter в 8 локалях, подразделы CLI-flow в §5/§7/§14, блок README в 8 локалях, ссылка Playwright#/apply, карточка порогов оценок#/reports) + Сценарий 18 (паритет справочного бандла) для регрессии паритета i18n.
Вне рамок (отложено)
| Пункт | Почему |
|---|---|
| SPA-страница batch evaluate | Canonical docs описывают только CLI-поток; SPA-эквивалент — новый view + ≥3 эндпоинта + фикстуры. Многодневная фаза. |
| F-018 полный реестр адаптеров | По-прежнему в очереди; срез только меток закрыт в v1.10.3. |
| Полный конвейер multer | v1.10.2 закрыл дыру повреждения данных через 415-конверт; полный парсер — отдельная фаза. |
Состояние тестов
- 348 / 349 unit (1 pre-existing дрейф родительских данных).
- Покрытие: 94.59 % line / 84.18 % branch.
- 20 / 20 smoke E2E · 23 / 23 comprehensive 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). Закрывает отсрочку PR-9 из v1.10.3.
📝 Документация
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). Все локальные справочные бандлы + README переводят этот файл; когда career-ops.org/docs меняется, регенерируется сначала этот файл.- Все 8 справочных бандлов (
docs/help/{en, ru, es, pt-BR, ko-KR, ja, zh-CN, zh-TW}.md) получили новый front-matter разделAbout career-opsсразу под H1-интро: принципы, ключевые концепции (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) и ссылки на все пять канонических руководств. Счётчик H2 сохранён на 16 на локаль (tests/help-ui.test.mjsпаритет остаётся зелёным). - Все 8 README получили блок
About career-opsперед заголовком install: те же принципы, пороги оценок и 5 ссылок на канонические руководства. РазделыWhat's new in v1.10.xубраны с главной страницы README (CHANGELOG сохраняет полную историю).
✨ Улучшения UI
#/apply— info-баннер теперь явно проявляет руководство по установке Playwright (career-ops.org/docs/.../set-up-playwright) и ссылку на canonical Apply-гайд. Новые ключи i18napply.playwrightHint+apply.docsLinkлокализованы в 8 локалях.
🔧 Внутреннее
- Путь к скриншоту README остаётся на
public/images/screen_vacancy_found.png(v1.10.1). - Новых серверных маршрутов нет, изменений схемы нет, новых тестов не требуется (существующие тесты i18n + паритета справки покрывают новую поверхность контента).
- Тест
tests/help-ui.test.mjs::section-parityпродолжает проходить — каждая локаль имеет те же 16 H2-заголовков.
Аудит (отложенные провалы, НЕ в этом релизе)
| Провал | Почему отложено |
|---|---|
SPA-страница batch evaluate (поток ./batch/batch-runner.sh) |
Canonical docs описывают только CLI-цикл (batch/batch-input.tsv → параллельный runner → batch/tracker-additions/). SPA-эквиваленту нужен новый view, три новых эндпоинта, фикстуры и тесты. Многодневная фаза; задокументировано в 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 pre-existing дрейф родительских данных в
portals-dead.test.mjs). - Покрытие: 94.59 % line / 84.24 % branch.
- 20 / 20 smoke E2E · 23 / 23 comprehensive E2E · 28 / 28 Playwright.
Документация
docs/reviews/REVIEW-2026-05-13-v1.11.0.md— контекст сессии + список провалов аудита UI.- Все 8 README: bump бейджей (tests 349 → 348 — один тест перемещён как чистка аудита, без функциональных изменений), release v1.10.3 → v1.11.0.
- Все 8 CHANGELOG получают эту запись.
[1.10.3] — 2026-05-12
Закрывает 7 из 11 QA-находок v1.10.0 (F-001, F-010 минимально, F-011 минимально, F-013, F-014, F-015, F-019). Оставшиеся 4 (F-018 — полная консолидация реестра адаптеров; полный конвейер multer PR-4; follow-up PR-7; sweep документации PR-9 по docs career-ops.org) перенесены в v1.11.0.
✨ Возможности
feat(pdf): Generate-PDF on every long-form surface (F-015)— три новых 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). Каждый вид переиспользует хелпер cv-markdown-to-print-HTML из v1.10.2 и приземляет результат вoutput/<slug>-<TS>.pdf, чтобы существующий поток автозагрузки подхватил его.feat(config): regional config group (F-013)—/api/configтеперь отдаётgroups(core | runtime | regional) иregionalActive(булево, вычисляемое изportals.yml::russian_portals.sources). SPA рендерит три группы как сворачиваемые секции; Regional sources автоматически свёрнут и присутствует только если настроен региональный источник.
🐛 Исправления
fix(server): global Express error handler (F-019)—PayloadTooLargeError(например, загрузка 11 МБ в/api/cv/import) иSyntaxErrorизexpress.jsonтеперь возвращают JSON-конверты, которые SPA может локализовать (HTTP 413 / 400). Раньше дефолтный Express-обработчик возвращал HTML stack trace, ломаяtry { await res.json() }в SPA.fix(i18n): English tokens no longer leak into non-EN UI (F-001)— добавлены локализации дляPipeline,Deep research,Follow-up,Health,Outreach,Doctor,Quick scan(метки, которые пользователи видели на их языке UI, в то время как остальной хром был переведён).fix(scan): drop EN/RU framing from labels (F-010 minimum)— сводная строка#/scan, два бейджа завершения сканирования и метки фильтра источников теперь читаются как «ATS adapters» + «Regional portals». Два 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 диспатчит событиеscan:refreshпосле каждогоrefreshResults(); счётчик пересчитывает «компании с попаданиями в последнем сканировании» из фактического payload/api/scan-resultsвместо застревания на снапшоте монтирования view.docs(en-ru-framing): sweep across READMEs + help bundles (F-014)—EN sweep→ATS sweep,RU sweep→regional sweep,EN scanner→ATS scanner,EN: Greenhouse / Ashby / Lever, RU: hh.ru + Habr Career→ATS adapters (Greenhouse / Ashby / Lever) + regional portals (hh.ru / Habr Career). ЗатрагиваетREADME.md,README.ru.md,README.ja.md,README.ko-KR.md,docs/help/en.md,docs/help/es.md,docs/help/pt-BR.md.
🧪 Тесты
- Новый
tests/global-error-handler.test.mjs(2 кейса): искажённый JSON → 400 JSON; загрузка 11 МБ → 413 JSON. - Новый
tests/config-groups.test.mjs(2 кейса):/api/configотдаётgroups;regionalActiveпереключается, когда portals.yml получает регионального источника. - Новый
tests/pdf-extra-routes.test.mjs(5 кейсов): каждый из/report,/deep,/inlineвызываетgenerate-pdf.mjsс тремя документированными позиционными аргументами; 404 на пропущенный slug; 400 на пустой inline markdown. - Итого: 349 / 350 unit (1 pre-existing дрейф родительских данных в
portals-dead.test.mjs). - Покрытие: 94.59 % line / 84.16 % branch.
- 20 / 20 smoke E2E, 23 / 23 comprehensive E2E, 28 / 28 Playwright.
📝 Документация
docs/reviews/REVIEW-2026-05-12-v1.10.3.md— контекст сессии + список scope-out.- Все 8 README: bump бейджей (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-адаптеров + новый
/api/stream/scan?source=, консолидирующий два существующих эндпоинта + +14 новых порталов + переписывание view сканирования). Срез только меток в этом релизе закрывает F-010 / F-011 визуально; архитектурный рефакторинг — многодневная фаза. - PR-4 — конвейер CV-импорта на multer (заменяет 415-конверт из v1.10.2 на настоящий парсер 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), перевести в 7 не-EN локалей, переписать справочные бандлы + README соответственно, провести аудит экранов UI против документированного поведения.
[1.10.2] — 2026-05-12
Патч функциональной регрессии. Закрыты два бага из ручного тестирования v1.10.1; поверхность документации расширена.
🐛 Исправления
fix(cv): /api/cv/import rejects multipart/form-data with 415 (F-016 hardening)— любой внешний клиент (curl-F, распространённые HTTP-клиенты), по умолчанию использующийmultipart/form-data, ранее сохранял свой wire-конверт (--boundary…\r\nContent-Disposition: form-data; name="file"; filename="x"…) как содержимоеcv.md. Фактический путь SPA (Content-Type: application/octet-stream+X-Filename) это не затрагивало. Маршрут теперь возвращает 415 с подсказкой на документированный контракт. Defense-in-depth: тела octet-stream, sniffing-щиеся как multipart в первых 256 байтах, также получают 415.cv.mdникогда не тронут при 415.fix(pdf): /api/stream/pdf invokes generate-pdf.mjs with proper positional args— раньше вызывал скрипт с[]. Скрипт печатал свою строкуUsage:и выходил с кодом 1 — SPA показывал зелёный toast «PDF generated», но ни один файл не попадал на диск. Маршрут теперь читаетcv.md, рендерит его в HTML-файл подoutput/cv-input-<TIMESTAMP>.htmlчерез in-route хелпер markdown-to-print-HTML, затем спавнитgenerate-pdf.mjs <input.html> <output.pdf> --format=a4. Опциональный query?format=letterдля вывода US-letter. Когдаcv.mdотсутствует, эмитит событиеerror+done { code: 2 }вместо фейкового кадра start.
🧪 Тесты
- Новый
tests/cv-upload-multipart-reject.test.mjs(5 кейсов): happy-path SPA возвращает 200 с чистым markdown;multipart/form-data→ 415; тело octet-stream, ВЫГЛЯДЯЩЕЕ как multipart, → 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). Один pre-existing провал в
portals-dead.test.mjsостаётся дрейфом данных на стороне родителя, не связан с web-ui. - Покрытие: 94.63 % line / 84.94 % branch.
📝 Документация
- Новый
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— полный контекст сессии, список scope-out, команды верификации. - Все 8 README: bump бейджей (tests 318 → 340, release v1.10.1 → v1.10.2) + раздел «What’s new in v1.10.2» на локаль.
- Все 8 CHANGELOG получают эту запись.
Вне рамок (отложено в будущие фазы GSD)
PR-1 локаленезависимый реестр адаптеров (по-прежнему в очереди), PR-4 CV-импорт на multer с полным конвейером конвертации, PR-7 кнопки Generate-PDF на reports / evaluate / deep / interview-prep, PR-8 перегруппировка UI конфигурации, PR-9 sweep документации, PR-10 покнопочный аудит локализации + шлюз jsdom CI, полный пересчёт корейского.
[1.10.1] — 2026-05-09
Патч критических правок по результатам регрессионного QA-запуска v1.10.0 (qa/reports/00-FINAL-SUMMARY.md).
🛡️ Безопасность
fix(security): tighten isValidJobUrl + add DNS-rebind defense (PR-3 / F-003)—isValidJobUrlтеперь отвергает RFC1918 (10/8,172.16/12,192.168/16), полный диапазон loopback 127/8, link-local169.254/16(включая AWS IMDS),0.0.0.0, CGNAT100.64/10и IPv6 ULA / link-local. Новый хелперisPrivateOrLoopbackHost()экспортирован изserver/lib/security.mjsи переиспользуется в/api/pipeline/preview, который теперь делаетdns.lookupна каждый редирект-хоп и отвергает, когда сам разрешённый адрес приватный — закрывает DNS-rebind. DNS-провал — fail-open (fetch сообщает об ошибке), чтобы тестовые stub / песочницы без DNS продолжали работать.
🐛 Исправления
fix(activity): record only successful state changes (PR-5 / F-005)— middleware теперь рано выходит наres.statusCode >= 400. Отклонённые запросы pipeline / cv / tracker больше не засоряют ленту аудита.fix(activity): add profile.save / config.save / cv.import event mappings (F-008)— успешные вызовыPUT /api/profileиPOST /api/configтеперь появляются в/api/activity.fix(help): alias ko → ko-KR.md so Korean Help body is served (F-002)— SPA шлёт голые BCP-47 коды (ko); файл на диске —ko-KR.md. Резолвер теперь обходит 4 кандидата: точное совпадение, alias с региональным тегом, базовый только-язык, затемen.md.fix(llm): /api/evaluate honors mode:'manual' (F-009)— зеркало/api/deep. Ручной режим пропускает вызовы Anthropic / Gemini даже при заданном ключе, чтобы пользователи могли копировать промпт в Claude Code, не сжигая кредиты.fix(api): DELETE /api/pipeline accepts ?url= AND body.url, returns 404 on miss (PR-6 / F-017)— раньше тихо 200-on-miss с только?url=.
✨ Возможности
feat(llm): locale propagation through every prompt (PR-2 / F-012)— новыйresolveLocale(req)выбирает локаль изbody.lang→body.locale→Accept-Language→'en'. НоваяbuildLocaleDirective(lang)эмитит однострочный заголовок «Respond in X».buildEvaluationPrompt,buildDeepPrompt,buildModePromptтеперь принимают и встраиваютlang. SPAAPI.call()автоматически прицепляетAccept-Languageи сливаетlangв JSON-тела.feat(scripts): post-qa-cleanup.mjs (PR-11)— проигрывает чек-лист пост-QA-чистки;--applyпишет, по умолчанию dry-run, идемпотентен. Подметает URL RFC1918 /nip.io/test-cloud-*изdata/pipeline.mdи проверяет размерcv.md.
🧪 Тесты
- Новый
tests/critical-fixes.test.mjs(15 кейсов), покрывающий: F-002 разрешение alias ko, F-009 опт-аут ручного режима, форму DELETE PR-6 (body / 404 / 400), модульные тесты хелпера PR-3 для IPv4 + IPv6 + форм в скобках, приоритет PR-2resolveLocale+buildLocaleDirective+ интеграцию построителей промптов. tests/url-validation.test.mjsрасширен 5 новыми тестами для RFC1918 / link-local / 0.0.0.0 / 127/8 / CGNAT / IPv6 ULA / link-local.- Тест 8 в
tests/activity-log.test.mjsобновлён, чтобы утверждать новый контракт «нет лога на 4xx». - Итого: 318 unit-тестов (было 298; один pre-existing провал в
portals-dead.test.mjs— дрейф данных на стороне родителя вtemplates/portals.example.yml, не связан с кодом web-ui).
📝 Документация
- Новый
docs/reviews/REVIEW-2026-05-09-v1.10.1.md— полный контекст сессии + список scope-out + команды верификации. - Все 8 README: bump бейджей (счётчик тестов 298 → 318, release v1.10.0 → v1.10.1), путь скриншота перенесён в
public/images/screen_vacancy_found.png, добавлен раздел «What’s new in v1.10.1» на локаль (English, Spanish, Portuguese, Korean, Japanese, Russian, Simplified Chinese, Traditional Chinese). - Все 8 CHANGELOG обновлены этой записью.
Вне рамок (отложено в будущие фазы GSD)
PR-1 (локаленезависимый реестр адаптеров, +14 порталов, переписывание FE), PR-4 (CV-импорт на multer + ConversionError + глобальный обработчик ошибок), PR-7 (кнопки Generate-PDF на reports / evaluate / deep / interview-prep), PR-8 (перегруппировка UI конфигурации), PR-9 (полный sweep EN-RU framing по README/docs/8-help bundle), PR-10 (покнопочный аудит локализации + шлюз jsdom CI), полный пересчёт корейского справочника (файл существует; PR только исправил runtime-доставку).
[1.10.0] — 2026-05-08
Переработка CV-импорта + вкладки #/config + канонический маршрут #/profile.
✨ Возможности
feat(cv): server-side import for .docx / .doc / .odt / .rtf / .pdf / .html / .txt / .md— новый эндпоинтPOST /api/cv/importконвертирует загруженный документ (в любом распространённом формате) в markdown, который редактор может вставить. Офисные форматы идут через pandoc, PDF — через pdftotext из Poppler. Результат санитайзится черезstripDangerousMarkdown(defense-in-depth XSS). Жёсткий лимит: 10 МБ на загрузку. Фронтенд📁 Upload CVтеперь принимает полный набор форматов; красивые toast-сообщения, когда конвертер отсутствует на хосте.feat(cv): auto-download generated PDF when generate-pdf.mjs finishes— потоковый поток Generate-PDF теперь снимает снапшот последнего PDF в директории output и наdoneинициирует загрузку браузером нового файла (no-op, если запуск не дал нового артефакта). Существующий on-page список по-прежнему показывает каждый предыдущий PDF.feat(config): two-tab layout — API keys & runtime + Profile—#/configтеперь имеет полосу вкладок. Первая вкладка сохраняет существующий редактор.env(API-ключи, модели, ручки сканера). Новая вкладка Profile — прямой YAML-редактор дляconfig/profile.yml:PUT /api/profileвалидирует YAML (должен быть mapping, должен включатьcandidate), штампует канонический заголовок# Career-Ops Profile Configuration, если он отсутствует, и пишет файл. Сохранение распространяется без перезапуска.feat(routes): canonical /#/profile route (was /#/settings)— сайдбар теперь указывает на#/profile. Старый хеш#/settingsещё резолвится через таблицу алиасов роутера, так что существующие закладки продолжают работать. Внутренний обработчик маршрута переименован; тесты обновлены, чтобы отражать новое направление.
🧪 Тесты
- Новый
tests/cv-import.test.mjs(7 кейсов): passthrough.md/.txt, пустое тело 400, неподдерживаемое расширение 422, оверсайз 413, санитайзинг HTML→markdown (пропускается, если pandoc отсутствует), round-trip PDF→текст с самодельным PDF (пропускается, если poppler отсутствует). - Новый
tests/profile-put.test.mjs(7 кейсов): happy-path round-trip, штамповка заголовка, 400 на empty / invalid-YAML / non-object / missing-candidate, оверсайз 413. tests/playwright-full-cycle.mjsрасширен 14 → 16 под-тестов — добавлены CV-импорт через HTML и round-tripPUT /api/profile.- Regex ALIAS в
tests/router.test.mjsразвёрнут, чтобы утверждать новое направлениеsettings → profile.
📚 Документация
docs/help/{en,ru}.md— полные обновления разделов 2/3/4: новые вкладки App-settings, сообщение edit-via-config на read-only странице Profile, полная матрица форматов загрузки в разделе CV, поведение автозагрузки PDF.docs/help/{es,pt-BR,ko-KR,ja,zh-CN,zh-TW}.md— лаконичные зеркала новых блоков контента; счётчик разделов без изменений (16), чтобы тест паритета оставался зелёным.
🔧 Внутреннее
- Новый
server/lib/cv-import.mjs— единый источник правды для конвертации формат → markdown, с таймаутом + обнаружением отсутствующего конвертера, проявляющим actionable-подсказки вместо 500. server/lib/routes/content.mjsполучаетPOST /api/cv/importиPUT /api/profile(binary-safe черезexpress.rawдля загрузки, JSON для YAML PUT).
[1.9.1] — 2026-05-08
Проход готовности к продакшну. Четыре прицельных bug-fix (BF-1..BF-4), Playwright smoke расширен с 5 до 12 тестов, покрывающих round-trip сохранения tracker / pipeline / reports / evaluate / config / cv. Всё зелёное в CI.
🐛 Исправления
fix(tracker): escape pipes + collapse newlines in every cell, not just notes (BF-1)— имя компании вида"Acme | Co"ранее ломало раскладку markdown-таблицы (парсер разрезал ячейку надвое). Санитайзер ячеек теперь применяется однообразно к company / role / reportSlug / notes; парная правка вparsers.mjs::parseMarkdownTableдобавляет поддержку экранирования\|по GFM, так что round-trip без потерь.fix(config): wrap updateEnvFile in try/catch (BF-2)—POST /api/configранее выбрасывал необработанное отклонение Promise при permission-denied / read-only ФС. Теперь возвращает чистый 500{ error: 'failed to write parent .env', details: [...] }.fix(llm): soft cap on assembled prompt size for Anthropic SDK calls (BF-3 + BF-4)— ветки Anthropic в/api/evaluate,/api/deepи/api/mode/:slugтеперь сдают 413, когдаbundleProjectContext + promptпревышает 200 КБ (≈50K токенов). Экономит несколько секунд раундтрипа + токены вместо того, чтобы дать API пожаловаться на размер контекста. Лимит значительно ниже любого текущего потолка модели (Sonnet 4.6 = 1M контекст).
🧪 Playwright smoke — расширение покрытия
5 → 12 тестов. Новые кейсы:
tracker view renders empty + accepts API-seeded row— упражняет BF-1, засевая строку с литеральным пайпом в имени компании и утверждая, что round-trip его сохраняет.pipeline add-URL form populates the queue+ проход отказа невалидных URL (loopback,javascript:, голые строки).reports view handles empty state— проверка отсутствия падения.evaluate view returns a manual prompt without API key— проверяет fallback-цепочку.config GET returns known keys masked— секреты никогда не утекают через/api/config.cv.md PUT round-trips with sanitization— XSS-ные куски (тэги script, схемыjavascript:) полностью санитайзятся.pipeline preview proxy strips scripts— путь отклонения невалидных URL.
📦 Изменения поведения (без изменений API-контракта)
- Записи в tracker теперь без потерь относительно имён company / role с пайпами. Существующие строки с сырыми пайпами начнут парситься правильно при следующем чтении.
/api/{evaluate,deep,mode/:slug}теперь возвращают 413 вместо 502/timeout, когда промпт неоправданно велик (200 КБ+).
🧪 Тесты
- 284 unit-теста (счётчик без изменений; существующие тесты остаются зелёными после обновления парсера).
- 12 Playwright browser-smoke тестов (было 5).
[1.9.0] — 2026-05-08
P-6 → P-10 из бэклога v1.8.0 отгружены одним пакетом. Главное: server/index.mjs теперь оркестратор на 130 LOC (с 762, всего 1230 → 130 = -89%); у каждой темы маршрутов свой модуль. Anthropic-паритет для /api/evaluate, шимы multi-CLI, расширенный тест паритета i18n и подключение Playwright browser-smoke в CI.
🏗️ P-6 — разделение сервера по сферам ответственности (фаза 2)
Продолжение P-2. Вынесены оставшиеся 9 тем маршрутов из server/index.mjs в модули server/lib/routes/<topic>.mjs. index.mjs теперь чистый оркестратор: middleware (security headers + activity log + static), 12 вызовов register<Topic>Routes(app) и catch-all SPA.
server/lib/routes/activity.mjs—/api/activity.server/lib/routes/config.mjs— GET/POST/api/config(round-trip родительского .env).server/lib/routes/health.mjs—/api/health+/api/dashboard.server/lib/routes/help.mjs—/api/help/:lang.server/lib/routes/jds.mjs— полный CRUD дляjds/*.txt.server/lib/routes/llm.mjs— каждый LLM-ориентированный эндпоинт (evaluate, deep, mode, apply-helper, interview-prep).server/lib/routes/pipeline.mjs—/api/pipeline*, включая SSRF-безопасный прокси preview с именованными константами для timeout / max-redirects / max-body.server/lib/routes/reports.mjs—/api/reports*.server/lib/routes/tracker.mjs— GET + dedup-aware POST/api/tracker.
Поведение без изменений. 283/283 unit-тестов оставались зелёными на каждом шаге. Поверхность импортов оркестратора упала с 47 строк до 22.
🔌 P-7 — Anthropic-паритет для /api/evaluate
/api/evaluate ранее был Gemini-or-manual. v1.9.0 добавляет ветку Anthropic (предпочтительна, когда оба ключа заданы), зеркалируя правило маршрутизации, уже используемое в /api/deep и /api/mode/:slug. Маршрутизируется через bundleProjectContext({ modeSlugs: ['_shared', 'oferta'] }), чтобы у модели были inlined cv / profile / шаблоны режимов (REVIEW-A1).
Новый эндпоинт: POST /api/evaluate/test-anthropic — smoke-проверка для ANTHROPIC_API_KEY, зеркало существующего Gemini-smoke. Шлёт крошечный промпт (≤256 выходных токенов), так что стоит фактически ничего; возвращает 200-символьную выборку.
Fallback-цепочка теперь: Anthropic → Gemini → manual.
🌐 P-8 — паритет 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 локаль весит как минимум 30 % от байтовой длиныen.md. Компактные переводы естественно попадают на 40-50 %; заглушка была бы в однозначных процентах.
Итог: структурный паритет теперь обеспечивается CI.
🤖 P-9 — Playwright browser smoke в матрице CI
tests/playwright-smoke.mjs (добавлен в v1.8.0 как опт-ин) теперь часть workflow CI. Существующая job e2e уже устанавливает Playwright + Chromium; один новый шаг (npm run test:e2e:browser) запускает 5 browser-smoke тестов сразу после comprehensive node E2E.
Порядок в CI: unit (матрица Node 18/20/22) → smoke node E2E → comprehensive node E2E → Playwright browser smoke → загрузка артефактов скриншотов при падении.
🌍 P-10 — Multi-CLI совместимость
Родительский career-ops v1.7.0 ввёл поддержку multi-CLI / Open Agent Skill standard. Подпроект UI следует тому же соглашению с тонкими шимами, указывающими на канонический CLAUDE.md:
web-ui/AGENTS.md— точка входа Codex / Aider / generic CLI.web-ui/GEMINI.md— точка входа Gemini CLI.
Оба шима повторно проговаривают жёсткие правила и quick reference, но делегируют CLAUDE.md полные инструкции уровня проекта, так что не-Claude CLI приземляются на ту же ориентацию, что и сессии Claude Code. Развёрнутый UI сам по себе остаётся CLI-агностичным в runtime.
🧪 Тесты
- 284 unit-теста (было 283): +1 новый тест паритета локалей справки.
- 5 Playwright browser-smoke тестов — теперь часть 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)
~ tests/help-ui.test.mjs (паритет всех-8-локалей + 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 |
Smoke-проверка ANTHROPIC_API_KEY (P-7). Зеркало /api/evaluate/test-gemini. |
🤖 Новые точки входа CLI
| Файл | CLI | Примечания |
|---|---|---|
AGENTS.md |
Codex / Aider / generic | Указывает на CLAUDE.md для полных инструкций. |
GEMINI.md |
Gemini CLI | Автоматически загружается Gemini при старте сессии. |
[1.8.0] — 2026-05-08
Усиление, рефакторинг и бутстрап SDD. Три исправления корректности/безопасности высокой серьёзности (A1, A2, A3), четыре средней (B1–B4), шесть чисток, аудит поверхности родительского career-ops v1.7.0, разделение сервера по сферам ответственности (P-2 фаза 1), Playwright browser-smoke и полный SDD-фундамент под docs/ и .claude/.
🔥 Исправления высокой серьёзности
fix(deep): inline cv/profile/mode files for Anthropic SDK calls (REVIEW-A1)—/api/deepи/api/mode/:slugранее говорили модели «сначала прочитай эти файлы», но у Anthropic SDK нет файловой системы. Вывод был пустым. НовыйbundleProjectContext({ modeSlugs })читаетcv.md,config/profile.yml,modes/_shared.mdи шаблон режима, обрезает каждый на 16 КБ и предваряет блоком<project_context>. Проверено вживую: 26 КБ обоснованного markdown-ответа отclaude-sonnet-4-6на вызов deep-research.fix(runner): SIGKILL escalation after SIGTERM grace period (REVIEW-A2)—runNodeScriptиstreamNodeScriptранее слали толькоSIGTERMна таймаут / отключение клиента. Ребёнок, застрявший в syscall (DNS, заблокированный сокет), игнорировал его, подвешивая SSE-соединение до того, как GC Node его съест. Теперь каждый путь вооружает 5-секундный сторожевой таймер, эскалирующий доSIGKILL. Promise всегда резолвятся.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, завершить ответ.
🛡️ Исправления средней серьёзности
fix(preview): per-hop redirect validation in /api/pipeline/preview (REVIEW-B1)— переключение сredirect: 'follow'на ручной обход редиректов. Каждый заголовокLocationповторно валидируется черезisValidJobUrl; лимит 3 хопа. Враждебные борды больше не могут отбросить нас на loopback / приватные IP /file://. 4 новых теста покрывают пути отклонения.refactor(keys): hasGeminiKey helper unifies LLM-key checks (REVIEW-B2)— прямые чтенияprocess.env.GEMINI_API_KEYв обработчиках маршрутов заменены наhasGeminiKey()изlib/anthropic.mjs. Зеркало формыhasAnthropicKey()для согласованности и более простого мокинга.feat(scanners): thread AbortSignal through hh.ru, Habr, Greenhouse, Ashby, Lever (REVIEW-B3)— когда SSE-клиент отключается на середине сканирования, активные HTTP-fetch теперь прерываются, а не дорабатывают каждый запрос до конца, теряя события.runRuScanиrunEnScanпринимаютopts.signal; SSE-обработчики в/api/stream/scan-{ru,en}создаютAbortControllerи прерывают наres.close.test(anthropic): log-guard test prevents future API-key leaks via console (REVIEW-B4)— захватывает каждый вызовconsole.{log,info,warn,error,debug}во время happy + error путейrunAnthropic, утверждает нулевой вывод и что строка ключа-канарейки никогда не появляется. Defense-in-depth против будущей регрессииconsole.log(opts).
🧹 Полировка низкой серьёзности
fix(parsers): defense-in-depth URL gate inside addPipelineUrl (REVIEW-C4)— отклонение значений не-http(s) на уровне парсера, дополняющее route-levelisValidJobUrl. Опциональныйopts.validateдля вызывающих, которым нужны более строгие правила.docs(readme): badge "tests-88 passed" → "tests-277 passed" (REVIEW-C3)— отставал на порядок.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— regex санитайзеров уже были в шестнадцатеричной форме\x00-\x08; запись ревью была артефактом рендеринга инструмента.
🏗️ P-2 фаза 1 — разделение сервера по сферам ответственности
server/index.mjs был 1230 LOC, значительно за потолком в 800 строк. Разделён на сфокусированные модули без изменения поведения. Все 283 unit-теста остались зелёными на каждом шаге.
server/lib/security.mjs—isValidJobUrl,stripDangerousMarkdown,sanitizeJobDescription,isPubliclyExposed. Реэкспортируется изindex.mjsдля обратной совместимости с внешними потребителями.server/lib/prompts.mjs—bundleProjectContext,buildEvaluationPrompt,buildDeepPrompt,buildModePrompt,buildApplyChecklist.server/lib/store.mjs—safeReadApps,safeReadPipeline,safeListReports,checkProfileCustomized,ensureRussianPortalsDefaults.server/lib/routes/scan.mjs—registerScanRoutes(app)для/api/stream/scan-{ru,en},/api/scan-ru/config,/api/scan-results.server/lib/routes/runners.mjs—registerRunnerRoutes(app)для буферизованной таблицы/api/run/*, потоковых/api/stream/{scan,liveness,pdf}, списка/загрузки сгенерированных PDF.server/lib/routes/content.mjs—registerContentRoutes(app)для CV / Profile / Portals / Modes.
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:
- Каталог режимов вырос с 7 до 19 файлов.
MODE_ALLOWLISTв UI намеренно проявляет только 7 (другие — только для Claude-Code). Добавлен комментарий, поясняющий намеренно узкие рамки. - Схема
portals.ymlподтверждена:tracked_companies(96 записей, 87 включено, 71 с API). EN-сканер читает её правильно; ключ legacycompaniesещё поддерживается. - Новые поверхности родителя, НЕ потребляемые сегодня:
dashboard/(Go-программа),update-system.mjs,generate-latex.mjs,analyze-patterns.mjs,liveness-core.mjs,followup-cadence.mjs,test-all.mjs, локализованные субдиры режимов (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 теперь полный фундамент Spec-Driven Development, выровненный с pipeline GSD (gsd-* skills из superpowers@claude-plugins-official).
CLAUDE.md(root) — системный промпт уровня проекта: стек, pipeline GSD, жёсткие правила (контракт с родителем, envelope безопасности, никаких--no-verify), соглашения, граница родительского проекта..aiignore— список исключений для AI-агентов: vendored, бинарники, пользовательские данные родителя,.planning/,.env, дубликаты локалей..claude/agents/— три определения проектных subagent:web-ui-route-reviewer.md— фильтрует новые маршруты против SSRF, CSP, санитайзеров, контракта родительской записи, соглашений, тестов.spa-view-reviewer.md— CSP-safe DOM, i18n, регистрация в роутере, доступность.test-isolation-reviewer.md— проверяет CI-изоляцию тестов (без допущений о родительском проекте, без живой сети, без коллизии портов).
.claude/commands/— заглушки слэш-команд:/sdd-status,/codebase-tour.- Дерево
docs/— всё на английском:PROJECT.md— что/зачем/для-кого, рамки, ограничения, критерии успеха.ROADMAP.md— текущий milestone + завершённая история + бэклог.sdd/SDD-GUIDE.md— pipeline discuss → spec → plan → execute → verify → review, привязанный к skillgsd-*.sdd/CONVENTIONS.md— модульная система, нейминг, маршруты, санитайзеры, клиентские паттерны, i18n, ошибки, логи, тесты, коммиты, ветки, CSS.architecture/OVERVIEW.md— диаграмма верхнего уровня, слои, последовательность загрузки, инварианты, чит-лист «куда смотреть, когда…».architecture/SERVER.md— карта по файлам дляserver/lib/*.mjs(обновлена для разделения P-2).architecture/FRONTEND.md— структура SPA, инвентарь view, глобалы, «как добавить view».architecture/API.md— полный инвентарь каждого маршрута/api/*.architecture/DATA-FLOWS.md— каждая родительская читка/запись с явным контрактом действия пользователя.reviews/REVIEW-2026-05-07.md— статический ревью, породивший правки этого changelog.
🔒 Безопасность и гигиена репо
chore(.gitignore): comprehensive defense-in-depth patterns— покрывает варианты env, папки IDE, GSD scratch (.planning/), пользовательские настройки агентов (.claude/settings.local.json,.claude/cache/,.claude/state/,.claude/memory/), артефакты Playwright (playwright-report/,test-results/,.playwright/,trace.zip), heap/CPU-профили, lock-файлы для неотгруженного тулинга, расширенный шум macOS Finder, общие паттерны секретов (secrets.json,credentials.json,*.pem,*.key).
🧪 Тесты
- 283 unit-теста (было 277): +11 новых (4 для отклонения редиректов B1, 1 для
hasGeminiKey, 1 для log-guardrunAnthropic). - 5 Playwright browser-smoke тестов (новые, опт-ин через
npm run test:e2e:browser): рендер дашборда + версия в подвале, навигация дашборд → scan → pipeline → cv, переключение языка, view 404, рендер страницы health. Резолвит Playwright через родительскиеnode_modules— без новой зависимости. - Покрытие сохранено на ~93% line / ~83% branch.
📝 Новые / обновлённые скрипты package.json
| Скрипт | Назначение |
|---|---|
npm run test:e2e:browser |
Запуск Playwright smoke harness против сервера in-process (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 (правка бейджа)
~ package.json (1.7.2 → 1.8.0)
~ server/index.mjs (1230 → 762 LOC)
~ server/lib/runner.mjs (эскалация SIGKILL, потолок max-runtime)
~ server/lib/anthropic.mjs (hasGeminiKey)
~ server/lib/parsers.mjs (фильтр URL в addPipelineUrl)
~ server/lib/ru-scanner.mjs ~ server/lib/en-scanner.mjs
~ server/lib/sources/{hh,habr,greenhouse,ashby,lever}.mjs (проброс signal)
~ tests/anthropic.test.mjs ~ tests/i18n-coverage.test.mjs
~ tests/pipeline-preview.test.mjs
career-ops-ui v1.267.1 · page 12/13 · mirror of the project changelog for cvstart.org