Historial de cambios
GitHubCada cambio relevante, versión a versión. El mismo archivo se publica en el repositorio y está traducido a los 19 idiomas.
[1.76.0] — 2026-06-26
Paridad con career-ops v1.13.0 — seis nuevas fuentes, refuerzo del escáner y tabla de resultados sin tope.
Añadido
- Seis fuentes ATS por inquilino — BambooHR, Breezy HR, Comeet, Personio, Recruitee, SolidJobs. Se autodetectan por el host de
careers_url(Comeet requiere elapi:completo); cada host se fija con regex anclado +redirect:'error'(anti-SSRF). Seleccionables en el desplegable Source de#/scan— el registro ahora trae 25 adaptadores (20 EN + 5 RU). AñadefetchTextpara el feed XML de Personio. trust_filter— puntuación de confianza opcional (0–100, nivel high/medium/low, flags), solo anota. Las filas bajohighmuestran una insignia ⚠ neutral en#/scan; nunca se descarta nada.- Arbeitsagentur
remoteMatch+remoteMaxPages— detección de remoto por configuración:title,filter(homeoffice=nv_truedel lado servidor + paginación) uoff.
Cambiado
- Sin tope de resultados. Se eliminó
MAX_STORED_RESULTS(2000) — se almacenan todas las coincidencias y la tabla#/scanlas pagina (200/pág.). - Robustez del filtro de título — los acrónimos cortos (COO, SDR…) coinciden por límites de palabra; una config
title_filtermal formada ya no rompe el escaneo. Ambos escáneres.
Pruebas
- +32 casos (1190 → 1222):
sources-ats-providers,title-filter,arbeitsagentur-remote,trust-validatory un guardiánscan-result-capreescrito («sin tope»).
[1.75.2] — 2026-06-19
docs: paridad documental completa para los agregadores del escáner de la v1.75.0 en los 12 idiomas. Sin cambio de código — alinea la documentación de cara al usuario con las siete fuentes que aterrizaron en la v1.75.0:
- Guía de ayuda (12 idiomas). §5 gana un bloque
content_filter(gating por palabras clave de descripción/fragmento, hermano delocation_filter) y una nota sobre agregadores; §7 enumera las siete nuevas fuentes en el barrido de escaneo de un clic y en la enumeración completa del desplegable Source; el recuento de adaptadores de §17 se corrige del obsoleto “11 adapters” a “19 adapters — 14 English + 5 Russian”. No se añadió ningún encabezado##/###, por lo que la estructura cerrada de 19 H2 / 75 H3 queda intacta. - README (9 idiomas completos). Nueva viñeta “Aggregator boards (v1.75.0)” bajo las fuentes de escaneo, más la insignia de versión actualizada a v1.75.2. (Los README abreviados pl/uk/ar no tienen lista por fuente y quedan intencionadamente intactos ahí.)
- Documentación de referencia.
docs/portals-examples.mdgana una sección “Aggregator boards” de copiar y pegar con bloques de configuraciónprovider:/<provider>:precisos para las siete;docs/PROJECT.mdactualizado a 19 adapters;docs/sdd/CONVENTIONS.mddocumenta la distinción de los dos registros (sources/registry.mjspara el desplegable frente aportals/registry.mjspara el fetching), la selección de agregador basada enprovider:enhebrada comoopts.company, el saneador de escritura de escaneo (scan-sanitize.mjs) y el recuento de tests de la v1.75.1 (1190). - QA. Añadido
qa/QA-REGRESSION-PROMPT-v1.75.2-FULL.md— el driver de compuerta de lanzamiento de superficie completa, renovado para el ciclo de agregadores de escaneo de la v1.75.x.
[1.75.1] — 2026-06-19
fix(scan): pulido de robustez sobre las fuentes basadas en configuración de la v1.75.0. Tres pequeñas correcciones de endurecimiento surgidas de la revisión posterior al lanzamiento (sin cambio de comportamiento para un escaneo sano):
- Pausas de paginación conscientes del abort. Las pausas de cortesía entre páginas de Glints (300 ms) y Jobstreet/SEEK (200 ms) ahora se resuelven de inmediato cuando se dispara el
AbortSignaldel escaneo, mediante un nuevo helperdelay(ms, signal)enserver/lib/http-json.mjs, de modo que un cliente desconectado no pueda mantener abierto un escaneo paginado durante una pausa extra. - Error descriptivo para respuestas no JSON.
fetchJsonahora envuelve un cuerpo2xxno JSON (p. ej. una página HTML de mantenimiento servida con estado 200) comonon-JSON 2xx response from <url>en lugar de exponer unSyntaxErrordesnudo, de modo que el registro de errores por fuente del escáner nombre el endpoint que se comporta mal. - Normalización de escritura de escaneo más fuerte.
normalizeScanScalarahora colapsa la tabulación vertical, el avance de página y los separadores Unicode de línea/párrafo (\v \f U+2028 U+2029) además de\r \n \t— un superconjunto estricto, de modo que ningún separador de registro/línea que una hoja de cálculo o un visor pudiera respetar sobreviva enscan-history.tsv.
[1.75.0] — 2026-06-19
feat(scan): incorpora la paridad con el career-ops padre v1.12.0 — siete nuevas fuentes de empleo, filtrado de contenido y correcciones de seguridad/calidad. La web-ui ejecuta sus propios escáneres en proceso (no delega en el scan.mjs del padre), por lo que los cambios de proveedor y de escaneo de la v1.12.0 del padre no se propagan automáticamente — esta versión reimplementa los aplicables conforme al contrato de adaptadores de la web-ui.
- Siete nuevas fuentes de escáner. Tres agregadores remotos de alcance global — RemoteOK, Remotive, Working Nomads — encajan en el patrón autodescubierto
server/lib/sources/*.mjs(se seleccionan conprovider: remoteok/remotive/workingnomads). Cuatro agregadores regionales basados en configuración — careers de IBM, Arbeitsagentur (Agencia Federal de Empleo alemana), Glints (Sudeste Asiático), Jobstreet / SEEK — leen un bloque de configuración<provider>:por entrada; el en-scanner ahora propaga la entrada de empresa resuelta hasta cada fetcher para que puedan leerla. Las siete aparecen automáticamente en el desplegable de fuentes de#/scan. content_filter(padre #974). Bloque opcional deportals.yml(listas de palabras clavepositive/negative) que filtra una oferta según el texto de su descripción/fragmento — refleja la semántica delocation_filter; las ofertas sin descripción siempre pasan. Integrado en los escáneres EN y RU.- Endurecimiento de la escritura de escaneo (padre #1098). Los metadatos de feeds externos se sanean ahora antes de aterrizar en
data/scan-history.tsvydata/pipeline.md: los caracteres de control se colapsan (un salto de línea en empresa/título ya no puede inyectar una fila TSV) y un= + - @inicial se neutraliza frente a la inyección de fórmulas de hoja de cálculo. secondaryLocationsde Ashby (padre #1073). La fuente Ashby ahora pliega la etiqueta de región de cada ubicación secundaria másaddressLocality/addressCountrypostal dentro de la cadena de ubicación (deduplicada), de modo que un puesto elegible para la UE cuya etiqueta principal diga p. ej. “Canada” aflore para ellocation_filter.- Validación de la forma del informe de evaluación (padre #819). Los proveedores en proceso de
/api/evaluate(Anthropic / OpenAI / Qwen / OpenRouter / GitHub Models) ahora marcan un informe A–G /SCORE_SUMMARYmalformado como un arraywarningsno fatal; la ruta de evaluación de Gemini ya hereda la salvaguarda delgemini-eval.mjsdel padre. - docs: Antigravity CLI añadido a las listas de asistentes compatibles en los 12 READMEs (se corresponde con el proveedor Gemini).
Heredado gratis del git pull del padre (la web-ui delega en estos): repliegue de fuentes CJK para PDF en japonés (#1053), fuentes PDF compatibles con ATS (#1074), salvaguarda CJK para LaTeX (#1054), correcciones de tracker/merge/followup/dashboard, y los modos chinos modes/zh (la web-ui lista los modos dinámicamente).
[1.74.3] — 2026-06-18
docs(parent-source): apunta el repo padre career-ops al fork Fighter90/career-ops. La web-ui ahora referencia el fork del mantenedor como proyecto padre en todos los puntos donde es una fuente real: el valor por defecto CAREER_OPS_REPO del instalador bin/setup.sh, cada enlace de git clone / “encima de” / onboarding en los 12 READMEs, y la documentación de agentes (CLAUDE.md, AGENTS.md, GEMINI.md, .github/copilot-instructions.md, docs/). El crédito al autor santifer (y el aviso de UI no oficial) no cambia — solo se movieron las URLs de origen/clonado. tests/sh-files.test.mjs ahora verifica que el instalador clona el fork.
[1.74.2] — 2026-06-17
fix(health): mostrar GITHUB_MODELS_API_KEY como verificación opcional en #/health y en /api/status/providers. El proveedor GitHub Models de la v1.74.0 era configurable en #/config, pero no tenía fila en la página de Salud y faltaba en la superficie de proveedores keysConfigured. Se añadió la verificación opcional (con la misma redacción “set / unset (manual mode)” que los otros cinco proveedores de evaluación en vivo) y github (+ su GITHUB_MODELS_MODEL) a /api/status/providers, de modo que el enrutamiento del proveedor activo y la página de Salud ahora reflejan los seis. La prueba de fila de salud de tests/api.test.mjs se amplió a los seis proveedores.
[1.74.1] — 2026-06-17
docs + test: sección “Instalar un asistente de IA” del README; cobertura completa de ramas para el conector de Gemini. Se añadió una tabla de instalación/inicio de sesión al README — enlaces de instalación para Claude Code / Gemini CLI / Codex / Qwen Code / OpenCode / GitHub Copilot CLI + la correspondencia de proveedor #/config de cada uno + “inicia sesión antes de continuar” (refleja el inicio rápido de career-ops.org/docs; aclara que la web-ui es la alternativa autónoma que no requiere CLI). El nuevo tests/gemini-connector.test.mjs (8 casos) cubre cada rama de runGemini — sin clave, éxito, error de API, finalización vacía/bloqueada, cuerpo malformado, tiempo de espera agotado, error de red, hasGeminiKey — llevando server/lib/gemini.mjs al 100% de sentencias. Cobertura global: 96% líneas / 88% ramas / 96% funciones. Suite 1126 → 1134.
[1.74.0] — 2026-06-17
feat(llm): GitHub Models (Copilot) como el 6.º proveedor + alineación canónica de 6 asistentes. career-ops.org/docs lista seis asistentes de codificación con IA — Claude Code, Gemini CLI, Codex, Qwen Code, OpenCode, GitHub Copilot CLI. La web-ui ahora admite los seis: cinco se corresponden con proveedores activos existentes (Anthropic / Gemini / OpenAI / Qwen / OpenRouter), y GitHub Copilot CLI obtiene un conector dedicado a GitHub Models — runGitHubModels (compatible con OpenAI-compatible; un PAT de GitHub con el alcance models), configurable en #/config (GITHUB_MODELS_API_KEY + GITHUB_MODELS_MODEL) y seleccionable mediante LLM_PROVIDER=github; 6.º en el orden auto. Los paquetes de ayuda y los READMEs ahora listan los seis canónicos (se renombró Qwen CLI→Qwen Code; se añadieron Gemini CLI + GitHub Copilot CLI), y el README incorpora una tabla completa de referencia de modos y enlaces a adaptadores de portales en career-ops.org/docs para que cada funcionalidad se pueda rastrear hasta el proyecto principal. tests/llm-provider-context.test.mjs extiende la matriz de límites de recuperación a los seis proveedores (cv.md + profile.yml integrados + artefacto devuelto); se añaden las nuevas claves GITHUB_MODELS_* a los 12 diccionarios de idiomas. Suite 1125 → 1126.
[1.73.0] — 2026-06-17
feat(llm): conector Gemini genérico + contexto CV/perfil verificado en todos los proveedores. Se añadió server/lib/gemini.mjs (runGemini) — un cliente Gemini generateContent sin dependencias externas que devuelve la misma forma {markdown, usage, error} que los clientes compatibles con Anthropic / OpenAI. Corrección: /api/mode/:slug y /api/deep anteriormente enrutaban sus prompts a través de gemini-eval.mjs, diseñado exclusivamente para ofertas, por lo que Gemini Run live devolvía una evaluación en lugar del artefacto solicitado (carta de presentación, alcance, resumen). Ahora llaman a runGemini con bundleProjectContext, de modo que cv.md + config/profile.yml se insertan en línea para Gemini exactamente igual que con cualquier otro proveedor — las cartas y resúmenes son detallados y personalizados. El nuevo tests/llm-provider-context.test.mjs simula el límite HTTP de cada proveedor y verifica que los cinco (Anthropic / Gemini / OpenAI / Qwen / OpenRouter) incluyan en línea cv.md + profile.yml y devuelvan el artefacto (matriz mode + deep + evaluate, 9 casos). /api/evaluate conserva su gemini-eval.mjs ajustado para ofertas. Suite 1116 → 1125.
[1.72.0] — 2026-06-17
feat(modes): Run live ahora devuelve el artefacto final directamente (contrato de salida de un solo disparo). Las plantillas padre modes/<slug>.md están escritas para sesiones interactivas de Claude Code — varias (cover, contacto, …) hacen una pausa para formular preguntas aclaratorias antes de producir el resultado, lo que hacía que el Run live de la interfaz web emitiera un cuestionario en lugar del artefacto. buildModePrompt ahora envuelve cada modo en un contrato de salida no interactivo: realiza el análisis (desglose de la oferta, notas sobre la empresa, palabras clave ATS, diferencias perfil↔oferta, elecciones de tono/enfoque) de forma silenciosa, elige valores predeterminados razonables de cv.md / config/profile.yml para todo lo que la plantilla normalmente preguntaría, y genera únicamente el artefacto final — cerrado con un recordatorio por modo «output ONLY {the cover letter / outreach message / …}». Así, al hacer clic en Run live sobre #/cover ahora se devuelve la carta de presentación en sí; la misma corrección se aplica a todos los modos genéricos (cover, contacto, interview-prep, project, training, followup, patterns) en los 12 idiomas (el artefacto se redacta en el idioma de la interfaz mediante la directiva de configuración regional). Suite 1103 → 1116.
[1.71.2] — 2026-06-17
docs(i18n): publica el pase de consistencia de documentación. El bloque “Translations of this guide” de cada README ahora lista los 11 idiomas hermanos (anteriormente algunos omitían English/Français o se enlazaban a sí mismos), con la línea en blanco antes del salto de sección restaurada. El prompt completo de regresión QA se renombra a la versión actual, y la documentación (CLAUDE.md, CONVENTIONS, LOCALIZATION, PROJECT-CONTEXT) se sincroniza con la versión actual y el recuento de pruebas (1103). Sin cambios en el código ni en el comportamiento — solo documentación, por lo que las traducciones de ayuda/UI y todas las funciones de 1.70.0–1.71.1 permanecen sin cambios.
[1.71.1] — 2026-06-17
fix(i18n): la guía de ayuda integrada está ahora completamente traducida en los 12 idiomas. Se añadieron docs/help/{pl,uk,ar}.md (cada uno con la estructura validada de 19 H2 / 75 H3) para que #/help sirva un paquete nativo en polaco, ucraniano y árabe en lugar de recurrir al inglés — GET /api/help/{pl,uk,ar} ahora devuelven su propia configuración regional. Integrado en todas las comprobaciones de ayuda (help-ui, help.test, help-ru-config-section, canonical-docs-coverage). También se completaron todas las listas de traducción en 12 idiomas: el bloque «Translations of this guide» del README (9 READMEs), las cabeceras «Translations:» de los CHANGELOG localizados (8 archivos) y se actualizaron los recuentos de documentación obsoletos. Suite 1100 → 1103.
[1.71.0] — 2026-06-16
feat(cover): genera un PDF de carta de presentación directamente desde #/cover. El modo cover (añadido en v1.70.0) produce el texto de la carta; el resultado ofrece ahora un botón Generate PDF que lo renderiza a través del pipeline compartido de markdown→PDF en línea (POST /api/stream/pdf/inline → generate-pdf.mjs), la misma ruta que usa interview-prep. Ahora puedes generar la carta y producir un PDF sin salir del SPA.
test/docs: endurecimiento de revisión de v1.70.0. Se añadió cobertura CI-aislada para el modo cover (lista de permisos + ensamblado de prompt), el selector <select> de banderas + RTL árabe (dirFor/<html dir>), top.langLabel en cada locale, el cableado del PDF de carta de presentación, y la directiva de locale de prompts.mjs + scaffolding para fr/pl/uk/ar. Se actualizaron las referencias obsoletas «todos los 8» → 12 locales en docs/sdd/CONVENTIONS.md y el prompt de regresión QA del proyecto completo.
[1.70.0] — 2026-06-16
feat(i18n): tres nuevos idiomas de interfaz — polaco (pl), ucraniano (uk) y árabe (ar, con RTL completo) — llevando la SPA a 12 idiomas, que coinciden con todos los idiomas del README del proyecto padre career-ops. Cada nuevo idioma incluye un diccionario completo de 697 claves (public/js/lib/locales/i18n-dict.{pl,uk,ar}.js), validado por las suites existentes de paridad / cobertura / sin-fugas-latinas / sin-datos-personales. El árabe añade soporte genuino de derecha a izquierda: i18n.js establece <html dir="rtl"> para idiomas RTL y un bloque [dir="rtl"] con alcance limitado en app.css refleja la interfaz (barra lateral, cajón de notificaciones, tablas y citas en markdown, espaciado en línea) — los idiomas LTR permanecen byte a byte sin cambios. Nueva clave top.langLabel (×12) nombra el selector para lectores de pantalla.
feat(ui): el selector de idioma <select> con icono de bandera reemplaza la fila de botones envolventes. Con 12 idiomas, la antigua fila .lang-btn se desbordaba en tres líneas en la barra lateral; un <select> nativo (cada opción precedida por un emoji de bandera) escala limpiamente, es compatible con teclado y lectores de pantalla de serie, y se mantiene seguro con CSP (manejador de cambio mediante addEventListener, sin JS en línea). Las banderas degradan a letras de región donde la plataforma carece de glifos de bandera, por lo que la etiqueta del idioma es siempre el identificador principal.
feat(cover): se porta el modo de carta de presentación del proyecto padre (career-ops v1.10.0 + saludo de v1.11.0) a la SPA. Nueva página #/cover dentro del grupo de navegación de Solicitud, construida sobre el ejecutor de modos genérico: descripción del puesto + empresa/rol + un saludo opcional → una carta personalizada generada a partir de cv.md / modes/_profile.md. Se añadió cover a la lista MODE_ALLOWLIST del servidor y un bloque i18n cover.* (×12 idiomas).
chore(compat): seguimiento del proyecto padre career-ops v1.11.0. Se verificó que el contrato de lectura/escritura está intacto — data/applications.md sigue siendo la fuente de verdad en markdown (el índice de seguimiento SQLite de v1.11.0 es una caché derivada), las columnas del seguimiento siguen siendo mapeadas por encabezado. parentVersion ahora indica 1.11.0.
fix(i18n): se cierra una brecha latente donde el francés (añadido en v1.61.0) faltaba en server/lib/prompts.mjs en LOCALE_NAMES y SCAFFOLD_STRINGS — las llamadas LLM en francés caían silenciosamente a la salida en inglés y andamiaje en inglés. fr/pl/uk/ar están ahora todos conectados al camino de configuración regional del prompt.
Seguimientos conocidos: la guía de ayuda integrada (
docs/help/) vuelve al inglés para pl/uk/ar (la interfaz en sí está completamente localizada); la entrevista de incorporación interactiva del proyecto padre, el descubrimiento ATS inverso y los nuevos proveedores de escaneo aún no están disponibles en la SPA.
[1.69.2] — 2026-06-12
fix(test): corrige una fuga de aislamiento de tests que permitía que npm test sobrescribiera tus config/profile.yml y data/scan-history.tsv reales. tests/critical-fixes.test.mjs importaba prompts.mjs (→ paths.mjs) en la parte superior del archivo, así que PROJECT_ROOT se resolvía al directorio padre real antes de que before() fijara CAREER_OPS_ROOT a un directorio temporal — y PUT /api/profile filtraba la fixture «Acceptance Test» a tu perfil real en cada ejecución. Solución: cargar prompts.mjs mediante import() dinámico dentro de before(). Nuevo tests/test-root-isolation.test.mjs (2 casos) protege toda la suite frente a ese patrón. Sin cambios de código de producción. Suite 1084 → 1086.
[1.69.1] — 2026-06-12
fix(scan): #/scan ya no trunca silenciosamente los barridos regionales grandes. El conjunto mostrado por región estaba limitado a 500 (un escaneo RU real de 1352 ofertas coincidentes mostraba solo 500; 852 ocultas — el síntoma «2000 escaneadas, ~600 mostradas»). Ambos escáneres usan ahora una constante compartida y configurable por entorno MAX_STORED_RESULTS (por defecto 2000, anulable con SCAN_MAX_RESULTS). Solo afecta a la visualización: las adiciones a pipeline.md / scan-history.tsv ya usaban el conjunto sin recortar. fix(health/ui): las tarjetas de comprobación de #/health ya no se desbordan. Un nombre/valor largo chocaba con el botón Fix → y la insignia de estado; la fila ahora se encoge y se ajusta mediante .health-check-row. Nuevas pruebas scan-result-cap + health-card-overflow. Suite 1079 → 1084.
[1.69.0] — 2026-06-12
feat(scan): autodescubrimiento de adaptadores del escáner (P-14) — basta con dejar un .mjs en server/lib/sources/ para registrar una nueva fuente. Antes de v1.69, la lista de fuentes en server/lib/sources/registry.mjs era un arreglo estático mantenido a mano: añadir un adaptador exigía editar tanto <id>.mjs como registry.mjs. Cierra la mitad pendiente del ítem P-14 de la hoja de ruta (docs/ROADMAP.md). Ahora cada *.mjs de server/lib/sources/ se carga dinámicamente al arrancar el módulo; cada adaptador declara su identidad mediante un bloque autodescriptivo export const meta = { value, label, region, configKey? }. Los 12 adaptadores incluidos (ashby / greenhouse / lever / rss / smartrecruiters / workable / workday + geekjob / getmatch / habr / hh / trudvsem) reciben un meta; registry.mjs usa readdirSync + import() dinámico resuelto vía top-level await (estándar ESM Node 18+). La API pública (SOURCES, SOURCES_BY_REGION, RU_CONFIG_KEYS, getRegionalSources) no cambia: todos los imports existentes siguen funcionando. La validación rechaza meta mal formados y registra un console.warn por archivo problemático. Nuevo tests/sources-registry-discovery.test.mjs con 14 casos. Suite 1065 → 1079.
[1.68.2] — 2026-06-07
fix(bin): los verbos de la CLI vía npx / npm link estaban rotos — la ruta del bin ahora se resuelve a través de enlaces simbólicos. npm y npx exponen career-ops-ui como un enlace simbólico bajo node_modules/.bin/, donde el antiguo dirname "${BASH_SOURCE[0]}" apuntaba a .bin en lugar de a la raíz del paquete, por lo que npx career-ops-ui init ejecutaba node node_modules/scripts/init.mjs y fallaba con MODULE_NOT_FOUND (las ejecuciones locales tras npm install no se veían afectadas, lo que ocultaba el fallo). Ahora bin/career-ops-ui.sh y bin/start.sh canonizan SCRIPT_DIR a través de la cadena de enlaces (bucle readlink + cd -P), de modo que cada verbo funciona desde el repo, vía npm link y vía npx. Añade un bloqueo de regresión en tests/sh-files.test.mjs que ejecuta un verbo a través de un enlace simbólico estilo .bin. Suite 1065/1065.
[1.68.1] — 2026-05-29
fix(scan): timeout de fetch por fuente 10s → 60s. El fail-fast de 10s de v1.67.1 también cortaba tableros Ashby lentos pero vivos que solo necesitaban más tiempo. Sube el valor por defecto a un minuto para que esos respondan. Compensación: una fuente realmente muerta/colgada ahora ocupa una ranura de concurrencia durante los 60s completos (escaneo peor-caso más lento), y los que se cuelgan crónicamente (Perplexity, Supabase, Resend, …) probablemente sigan caducando — un arreglo por fuente / menor concurrencia de Ashby los resolvería bien. Override con SCAN_FETCH_TIMEOUT_MS. Suite 1063/1063.
[1.68.0] — 2026-05-29
feat(scan): panel de filtros de resultados rediseñado — campos con etiqueta, botón Aplicar, opción Presencial y un filtro de salario que funciona. Cada filtro de #/scan es ahora un campo con etiqueta (etiqueta encima del control, no un placeholder): Buscar · Tipo · Salario desde · Salario hasta · Fuente · Alcance. Un botón Aplicar explícito (más Restablecer, y Enter en cualquier campo) reejecuta el filtro; una pista en la página explica cómo funciona. El rango salarial ahora filtra de verdad — al fijar un valor desde/hasta, los empleos cuya remuneración queda fuera del rango y los empleos sin salario indicado se descartan (solape de rangos; se ignora la divisa). El filtro de Tipo gana una opción Presencial junto a Remoto / Híbrido / Reubicación. Nuevas claves i18n ×9; salaryInRange ahora estricto; suite 1063/1063.
[1.67.1] — 2026-05-29
fix(scan): timeout de fetch por fuente 30s → 10s (fail-fast). La subida a 30s de v1.67.0 solo recuperó ~la mitad de los tableros Ashby lentos; el resto (Perplexity, Supabase, Resend, DeepL, Ramp, …) se cuelgan sin importar el deadline, así que un timeout mayor solo estancaba cada escaneo esperando ranuras muertas. 10s falla rápido en los que se cuelgan crónicamente y mantiene los escaneos ágiles. Override con SCAN_FETCH_TIMEOUT_MS. Suite 1060/1060.
[1.67.0] — 2026-05-29
feat(scan): filtro de rango salarial (desde / hasta) en #/scan, y un timeout de fetch por fuente más largo. La tabla de resultados gana dos campos numéricos — salario desde / hasta — junto a los filtros de texto y remoto. El salario en texto libre de cada fila (от 100 000 до 200 000 ₽, 120000-150000 USD, $120K–$150K, …) se parsea a un rango numérico y se compara con semántica de rangos solapados; las filas sin salario publicado se conservan, así el filtro acota la lista en vez de vaciarla (la comparación ignora la divisa — sin conversión de cambio). También sube el timeout de fetch por fuente de 15s → 30s (override: SCAN_FETCH_TIMEOUT_MS): los payloads includeCompensation de Ashby tardaban habitualmente >15s con concurrencia ×8, así que ~30 tableros Ashby caían por timeout en cada escaneo. Nuevos window.Skills.parseSalaryRange/salaryInRange + i18n ×9; 13 pruebas nuevas; suite 1060/1060.
[1.66.0] — 2026-05-28
feat(scan): las fuentes RU ahora recorren TODAS las páginas, no solo la primera. hh.ru, Habr Career y Trudvsem solo paginaban los primeros ~50 resultados por consulta; ahora siguen la paginación hasta el final — &page=N para hh.ru/Habr, offset/meta.total para Trudvsem — deduplicando entre páginas y parando cuando una página no aporta nada nuevo (o en un tope de seguridad de 50 páginas). Una consulta como “Backend разработчик” devuelve ahora el conjunto completo (p. ej. hh.ru PHP 17 → 55+ en 3 páginas; Trudvsem devuelve los 72). Cada página conserva el timeout + AbortSignal. 4 pruebas nuevas; suite 1045/1045.
[1.65.0] — 2026-05-28
feat(scan): hh.ru ahora se scrapea desde su web pública en vez de la API JSON — funciona desde cualquier IP, sin proxy. api.hh.ru empezó a devolver un 403 forbidden a cualquier cliente programático sin importar la IP ni el User-Agent (un bloqueo anti-bot de borde). La web (hh.ru/search/vacancy) sí sirve resultados completos a cualquier cliente tipo navegador, así que el adaptador ahora parsea ese HTML (como Habr Career). Elimina la variable HH_PROXY de 1.64.0 y la dependencia undici — sin proxy, clave ni User-Agent. Tests reescritos para el parser HTML; suite 1041/1041.
[1.64.0] — 2026-05-27
feat(scan): enruta la petición a hh.ru por un proxy ruso mediante HH_PROXY. hh.ru bloquea su API por IP, no por User-Agent — por eso HH_USER_AGENT por sí solo nunca levantaba un 403 desde un nodo de salida no ruso. Define HH_PROXY con la URL de un proxy ruso HTTP/HTTPS (p. ej. http://user:pass@ru-host:port) y solo la petición a hh.ru pasa por él; las demás fuentes mantienen su conexión directa. Construido sobre el ProxyAgent de undici (nueva dependencia de runtime); el dispatcher se omite por completo cuando HH_PROXY no está definido. 3 pruebas nuevas; suite 1041/1041.
[1.63.2] — 2026-05-27
feat(scan): % de progreso en vivo + detalle por fuente en la consola de #/scan. La barra ahora es determinada — los escáneres emiten eventos de progreso (EN: por empresa; RU: por consulta) vía SSE, y la barra se llena con una etiqueta «Scanning… NN%» (la franja animada solo hasta el primer evento). El primer fallo de cada fuente (timeout / 403 / red) se registra en detalle en la consola; los repetidos se suprimen. 1 prueba nueva; suite 1040/1040.
[1.63.1] — 2026-05-27
style(scan): barra de progreso de #/scan más visible. El indicador ahora lleva un rótulo visible «Scanning…» y la barra pasó a 8px (antes 4px finos), claramente perceptible durante el escaneo. Sin cambios de comportamiento.
[1.63.0] — 2026-05-27
feat(scan): timeout por petición + barra de progreso en #/scan. Las peticiones de fuentes no tenían límite de tiempo, así que una fuente atascada (p. ej. api.hh.ru desde una IP bloqueada) podía colgar todo el escaneo. El nuevo server/lib/fetch-timeout.mjs envuelve el fetchImpl de los escáneres (makeTimeoutFetch, por defecto 15s, configurable con SCAN_FETCH_TIMEOUT_MS); una fuente expirada se registra como error no fatal y el escaneo continúa. #/scan muestra una barra de progreso durante el escaneo (scan.progress en las 9 localizaciones). 7 pruebas nuevas; suite 1039/1039.
[1.62.3] — 2026-05-27
docs: instalación aclarada (career-ops-ui corre dentro de career-ops/web-ui/) + solución de problemas de init, en las 9 localizaciones. Sección de instalación reescrita en Option 1 (un curl) / Option 2 (clonar la UI dentro de un proyecto career-ops existente como web-ui) + verbos CLI + configuración del proveedor + bloque Troubleshooting init. Nota de estructura anidada añadida a /help §1 Setup; resumen de toda la línea v1.62.* en el README. Solo documentación; sin cambios de código.
[1.62.2] — 2026-05-27
fix(help): el filtro de #/help ahora es de texto completo (encuentra subsecciones H3 como RSS). El filtro de búsqueda/TOC de la página de ayuda solo coincidía con títulos de sección H2, por lo que la documentación RSS de v1.62.x (un H3 bajo §5 Portals & sources) no se encontraba. Ahora el cuerpo de cada sección se indexa en el filtro, así que buscar p. ej. «RSS» muestra §5. Solo del lado del cliente; sin cambios de API.
[1.62.1] — 2026-05-27
feat(scan): RSS en el filtro de fuentes + corrección de ubicación RSS. El desplegable de filtro de fuentes en #/scan ahora incluye RSS (añadido a server/lib/sources/registry.mjs + la lista de respaldo del SPA), por lo que los resultados de portales RSS (LaraJobs, WeWorkRemotely, …) se filtran como cualquier fuente ATS. El adaptador RSS ya no asigna la etiqueta <category> del feed a location — esas etiquetas hacían que location_filter descartara erróneamente puestos remotos; ahora location queda vacío y los feeds pasan el filtro de ubicación. Tooltips/etiquetas del botón de escaneo y la cadena de lista de fuentes actualizadas en las 9 localizaciones (Workable / SmartRecruiters / Workday / RSS). Snapshot i18n y prueba del endpoint de fuentes (6 → 7 EN) actualizados.
[1.62.0] — 2026-05-27
feat(scan): adaptador RSS genérico para portales de empleo no-ATS. Un nuevo adaptador rss (server/lib/portals/adapters/rss.mjs + server/lib/sources/rss.mjs) permite al escáner extraer ofertas de cualquier feed RSS — LaraJobs, WeWorkRemotely, RemoteOK, golangprojects y otros portales fuera de Greenhouse/Ashby/Lever. Sin nuevas dependencias: el análisis del feed usa regex con soporte de CDATA y entidades HTML (títulos/empresas sin etiquetas, code points astrales decodificados de forma segura). Se activa por empresa con provider: rss / rss: / feed_url: en portals.yml, sin interceptar empresas ya emparejadas con ATS. ALL_ADAPTERS crece 6 → 7. 29 nuevas pruebas; documentado en las 9 localizaciones del README.
[1.61.1] — 2026-05-22
fix(i18n): localiza el title + aria-label del conmutador de tema en los 9 idiomas (MINOR-001). El botón de tema claro/oscuro (#theme-toggle) tenía title="Toggle theme" y aria-label="Toggle theme" codificados en index.html — el tooltip y el texto para lectores de pantalla nunca se traducían, en ningún idioma. Nueva clave top.themeToggle + un manejador data-i18n-title en applyI18n() (espejo del arreglo de aria-label de búsqueda de v1.58.15) localizan ambos atributos al arrancar y en cada cambio de idioma. Bloqueado por tests/playwright-theme-toggle-i18n.mjs (9 idiomas + cambio en runtime) y dos guardas estáticas. Único hallazgo LOW del sign-off de v1.61.0. (MINOR-001)
[1.61.0] — 2026-05-22
feat(i18n): añade el francés como 9.º idioma de la interfaz. Nuevo diccionario por idioma public/js/lib/locales/i18n-dict.fr.js (window.__I18N_DICT_FR), con paridad completa de 668 claves con el inglés; nuevo paquete de ayuda docs/help/fr.md (19 H2 / 73 H3, paridad estructural exacta con en). fr queda registrado en el conmutador de idioma y la autodetección del navegador (i18n.js), en el ensamblador (i18n-dict.js), en index.html (etiqueta <script> antes del ensamblador), en el snapshot de test y en todas las listas de locales de los tests. La tabla de traducción inicial proviene de la PR #9 (contribución de la comunidad). Sin cambios de lógica: t() y todas las vistas no cambian. 1001 / 1001 pruebas unitarias; el barrido de locales de Playwright crece a 9 subtests. (FR-LOCALE)
[1.60.0] — 2026-05-22
refactor(i18n): divide el megaarchivo de 8 columnas en archivos por idioma (I18N-SPLIT). El diccionario de traducciones vivía en un único public/js/lib/i18n-dict.js; ahora hay un archivo por idioma en public/js/lib/locales/ más i18n-dict.aliases.js, para que un traductor edite un solo idioma de forma aislada (estilo i18next / OpenWA). i18n-dict.js es ahora un ensamblador que reconstruye exactamente el mismo window.__I18N_DICT, así que t() y todas las vistas no cambian. Se carga de forma síncrona vía <script src> — sin paso de compilación ni fetch. Un snapshot demuestra que la migración no pierde nada (678 claves). Herramientas y ~25 tests adaptados; nuevos tests/i18n-locale-files.test.mjs y tests/playwright-locale-sweep.mjs (cada página × 8 idiomas en Chromium real). 994 → 1000 unitarios · 62 → 70 Playwright. Sin cambios de comportamiento. (I18N-SPLIT)
[1.59.13] — 2026-05-21
fix(i18n): colapsar claves duplicadas reales con @alias + purga final de datos personales. Nombre real del maintainer eliminado de fixtures de test y reportes QA (→ Jane Doe); LICENSE/package.json → handle Fighter90. Mecanismo @alias colapsa las 10 claves idénticas en los 8 locales; nav.config/config.title NO se fusionan (divergen en español). 991 → 994 tests. (I18N-CL3)
[1.59.12] — 2026-05-21
fix(i18n): limpieza de i18n-dict.js — pre-fr (I18N-CL1, I18N-CL2, I18N-CL4). Eliminado dato personal en training.coursePh (→ placeholder genérico), restaurado followup.lastPh como pista de formato (no fecha fija), añadido npm run audit:i18n. Los grupos de valores duplicados son intencionales (roles de UI distintos) — ver cabecera del diccionario. (I18N-CL1, I18N-CL2, I18N-CL4)
[1.59.11] — 2026-05-21
fix(test): v1.59.11 — la suite e2e-comprehensive ahora pasa 23/23 (era 11/23). Causa raíz: page.goto(baseUrl + '/#/X') es un no-op para cambios solo de hash en Playwright. El nuevo helper goRoute(hash) rebota por about:blank antes de cada goto y fuerza una navegación real. (e2e-harness-r1)
[1.59.10] — 2026-05-21
fix(api): NEW-F1-sub-r1 (v1.59.10) — middleware de .. crudo movido arriba de todas las rutas /api. El de v1.59.8 estaba después de app.all y nunca disparaba. Ahora corre antes de la normalización de Express. (NEW-F1-sub-r1)
[1.59.9] — 2026-05-21
fix(ux): UX-A5-r4 (v1.59.9) — marcador de debug data-toc-spy="active" + lock-test conductual del scroll-spy del Help TOC. Sexto ciclo: las 5 cerraduras anteriores pasaron las pruebas estáticas pero el bug persistía. v1.59.9 añade marcador, paint inicial síncrono, re-compute con doble rAF, listener de resize, y limpieza completa en hashchange. (UX-A5-r4)
[1.59.8] — 2026-05-21
fix(ux+api): v1.59.8 — UX-A5-r3 + NEW-F1-sub (HIGH + LOW agrupados). Excepción de doctrina autorizada por el reporte FINAL-REGRESSION-v1.59.7. UX-A5-r3: #/help cambia el IntersectionObserver por un listener scroll con rAF throttling — tras 4 ciclos de fallos del IO, ahora el scroll-spy es robusto en todos los modos de scroll. NEW-F1-sub: middleware que rechaza .. crudos en /api/* con 404 JSON. (UX-A5-r3 · NEW-F1-sub)
[1.59.7] — 2026-05-20
fix(api): NEW-D3-cache (v1.59.7) — GET /api/cv envía Cache-Control: no-store. El CV es el artefacto principal del usuario; siempre revalidar. (NEW-D3-cache)
[1.59.6] — 2026-05-20
feat(a11y): NEW-D2-motion (v1.59.6) — respeto a prefers-reduced-motion: reduce. Nuevo bloque @media neutraliza animaciones, transiciones y scroll-behavior. (NEW-D2-motion)
[1.59.5] — 2026-05-20
fix(api): NEW-F1 (v1.59.5) — /api/* desconocido devuelve 404 JSON en cada verbo. app.get → app.all. (NEW-F1)
[1.59.4] — 2026-05-20
fix(ui): NEW-OR1 (v1.59.4) — chip Active/Keys en #/config ahora libre de races. Construye los nodos antes del swap, token de in-flight, caché del último estado bueno. (NEW-OR1)
[1.59.3] — 2026-05-20
fix(ux): UX-A5-r2 (v1.59.3) — scroll-spy en #/help reforzado. rootMargin ampliado de 10 % a 25 % de banda visible + estado inicial calculado al montar. (UX-A5-r2)
[1.59.2] — 2026-05-20
fix(ui): v1.59.2 — chip Active/Keys: cuenta correcta, nombre del proveedor capitalizado, sin solapamiento. (post-v1.59.1 hotfix)
[1.59.1] — 2026-05-20
fix(test): v1.59.1 — NEW-D1 guard acepta el copy ES pulido en UX-A11. Relajada la regex que bloqueaba pipe.title[es] a vacantes. Ahora también acepta candidaturas. (v1.59.1)
[1.59.0] — 2026-05-20
feat(ui): UX-A14 (v1.59.0) — Pase de auditoría mobile (≤ 420 px). Cinco correcciones en un nuevo bloque @media (max-width: 420px): card-row 1-up, hero CTAs apilados, page-header apilado, qa-grid floor 160 px, api-keys summary compacto. (UX-A14)
[1.58.65] — 2026-05-20
test(ui): UX-A2 (v1.58.65) — test de bloqueo del field-form estructurado de Modes. Nuevo test que protege la implementación v1.54.3 contra regresiones. (UX-A2)
[1.58.64] — 2026-05-20
fix(i18n): UX-A11 (v1.58.64) — pulido del copy en español. eval.subtitle ahora usa ajuste del CV, Puntaje, cabecera, informe. pipe.title ahora es Pipeline de candidaturas. (UX-A11)
[1.58.63] — 2026-05-20
fix(ui): UX-A15 (v1.58.63) — tile Pipeline del Dashboard con peso visual primario. El tile Pipeline ahora destaca con borde de acento, ícono más grande y etiqueta en negrita. (UX-A15)
[1.58.62] — 2026-05-20
feat(ui): UX-A9 (v1.58.62) — chip sticky de resumen en la pestaña API keys. #/config → API keys ahora muestra arriba un chip sticky con el proveedor activo y el conteo de claves configuradas. (UX-A9)
[1.58.61] — 2026-05-20
docs(readme): UX-A8 (v1.58.61) — sección de limpieza para primera ejecución añadida en los 8 READMEs. Ahora se documenta el paso make clean-test-fixtures para purgar las dos URLs fixture QA antes del primer scan. (UX-A8)
[1.58.60] — 2026-05-20
feat(ui): UX-A12 (v1.58.60) — Cajón de notificaciones con Borrar todo + descartar por entrada. Nuevo botón global y × por entrada en el panel de notificaciones. (UX-A12)
[1.58.59] — 2026-05-20
feat(ui): UX-A13 (v1.58.59) — CTA accionable «Fix →» en filas de salud que fallan. Las filas con FAIL/OPTIONAL ahora muestran un botón ghost que enlaza directamente con la pestaña de configuración correspondiente. (UX-A13)
[1.58.58] — 2026-05-20
fix(ux): UX-A10 (v1.58.58) — protección contra perder edición no guardada en #/cv. Ahora beforeunload (cierre del navegador) y hashchange (navegación SPA) muestran confirmación localizada antes de abandonar la página con buffer sucio. (UX-A10)
[1.58.57] — 2026-05-20
test(ui): UX-A7 (v1.58.57) — bloqueo de regresión sobre el contrato de refresco automático del cost-line. Nueva prueba estática asegura que el evento providers-changed se despacha, se suscribe y que todas las vistas de asesor llaman a UI.providerCostHint. (UX-A7)
[1.58.56] — 2026-05-20
fix(a11y): UX-A4 (v1.58.56) — .lang-btn cumple el tamaño mínimo de objetivo táctil WCAG 2.5.8. Antes los botones de idioma medían 23–25 px de alto, por debajo del piso de 24×24 px. Ahora min-height: 28px + min-width: 28px garantizan el cumplimiento WCAG 2.2 AA. (UX-A4)
[1.58.55] — 2026-05-20
feat(ui): UX-A3 (v1.58.55) — chip de proveedor activo en el Dashboard. El hero de #/dashboard ahora muestra qué proveedor LLM está activo (⚡ Live evals: Anthropic claude-sonnet-4-6 o 📋 Manual prompt mode). Se actualiza automáticamente al cambiar LLM_PROVIDER en #/config y al recuperar foco en la pestaña. (UX-A3)
[1.58.54] — 2026-05-20
fix(ux): UX-A1 (v1.58.54) — aviso defensivo de estructura para el brief de Deep. Cuando el brief guardado no incluye al menos 3 de las 6 secciones canónicas (Company snapshot / Engineering culture / Recent news / Glassdoor / Interview process / Negotiation leverage), public/js/views/deep.js antepone un aviso no bloqueante con enlace a la referencia. Solución a nivel de UI; la corrección en el prompt vive en el proyecto padre. (UX-A1)
[1.58.53] — 2026-05-20
fix(ux): UX-A6 — todo saved-card pasa por un único helper renderSavedCard(). Garantiza la estructura <span>+<time> en cada path de renderizado. 948 → 949 unitarios. (UX-A6)
[1.58.52] — 2026-05-20
fix(ux): UX-A5 — scroll-spy del TOC en #/help ahora dispara correctamente. Regresión de v1.58.45 (setTimeout(0) era demasiado temprano). Fix: refs directas a headings + doble requestAnimationFrame. 947 → 948 unitarios. (UX-A5)
[1.58.51] — 2026-05-20
chore(docs): v1.58.51 — limpieza final del ciclo v1.58.37 → v1.58.50 (14 releases). Sin cambios de código. qa/ reorganizado (todo lo version-locked en archive/v158-cycle/); 6 perennials en raíz. REGRESSION-FINAL §13 documenta cada invariante v1.58.37→.50. UX-AUDIT-PROMPT.md extendido. Baseline sin cambios (947/947). (housekeeping)
[1.58.50] — 2026-05-20
docs: DOC-1 — qa/REGRESSION-FINAL.md añade §5a documentando que los cuerpos de error del servidor son inglés-por-política. Cierra NEW-D4 como not-a-finding. Recomendación A del spec. Cierra la cola v1.58.37 → v1.58.50 de FIX-PROMPT-FINAL-EXHAUSTIVE.md (14 releases). 946 → 947 unitarios. (DOC-1)
[1.58.49] — 2026-05-20
chore(tooling): TOOL-1 — make clean-test-fixtures + script para eliminar líneas example.com de data/pipeline.md del proyecto padre. Soporta --dry-run. 4 tests CI-isolated. 942 → 946 unitarios. (TOOL-1)
[1.58.48] — 2026-05-20
fix(ux/onboarding): UX-D-B — banner global en #/dashboard cuando el perfil sigue en el template por defecto. Nuevo profileFixtureBanner() que muestra .hero-banner--warning al detectar Profile customized: false en /api/health. Nuevas claves i18n onboarding.fixtureWarning + onboarding.fixProfile × 8. 941 → 942 unitarios. (UX-D-B)
[1.58.47] — 2026-05-20
fix(ux/naming): UX-D-C — el botón “Quick scan” de la barra superior pasa a llamarse Abrir Scan para reflejar que solo navega (no inicia un scan). Actualizado en las 8 locales. 940 → 941 unitarios. (UX-D-C)
[1.58.46] — 2026-05-20
fix(ux): UX-D-D — checklist de #/apply sustituye {company}-{role} por slugs derivados del URL/JD. Antes los placeholders se mostraban literalmente. Nuevas funciones extractSlugs + substitutePlaceholders reconocen Greenhouse/Lever/Ashby/Workable/SmartRecruiters/Workday. Fallback [company]/[role]. 939 → 940 unitarios. (UX-D-D)
[1.58.45] — 2026-05-20
fix(ux): UX-D-K — scroll-spy en el TOC de #/help resalta la sección actual. IntersectionObserver aplica .toc-current al enlace cuyo H2 está en la banda de lectura. 938 → 939 unitarios. (UX-D-K)
[1.58.44] — 2026-05-20
fix(ux): UX-D-L — el brief abierto en Saved-research de #/deep tiene un botón × para cerrar. Antes no había forma de cerrar el brief sin desplazarse o navegar. Nueva clave deep.closeBrief × 8. 937 → 938 unitarios. (UX-D-L)
[1.58.43] — 2026-05-20
fix(ux): UX-D-F — submit vacío en #/evaluate muestra toast localizado distinto. Antes confundía vacío con “demasiado corto”. Nueva clave eval.emptyJd × 8. 936 → 937 unitarios. (UX-D-F)
[1.58.42] — 2026-05-20
fix(ux): UX-D-J — paridad del chip de ETA en todas las páginas de advisor. Antes solo #/auto mostraba “⏱ ~1–2 min”. Ahora también #/evaluate, #/deep, y las 5 mode-pages muestran ⏱ ~30s (clave advisor.eta × 8). 935 → 936 unitarios. (UX-D-J)
[1.58.41] — 2026-05-20
fix(ux/truthfulness): UX-D-I — la cost-hint vuelve a consultar al cambiar de pestaña + en evento providers-changed. Antes solo se cargaba una vez; ahora se re-fetch via visibilitychange + un CustomEvent que dispara #/config al guardar. 934 → 935 unitarios. (UX-D-I)
[1.58.40] — 2026-05-20
fix(ux/docs): UX-D-H — regression-lock para que toda URL career-ops.org/docs/... visible siga siendo clickeable. Nueva tests/external-doc-links.test.mjs valida views/.js y docs/help/.md. 932 → 934 unitarios. (UX-D-H)
[1.58.39] — 2026-05-20
fix(ux): NEW-D2 — botón Refresh en el header del panel con feedback explícito. Distinto del Refresh del banner de conexión; este re-fetch in-place sin recargar la página. 2 nuevas claves i18n. 931 → 932 unitarios. (NEW-D2)
[1.58.38] — 2026-05-20
fix(a11y): NEW-D3 (WCAG 4.1.2) — input de búsqueda de #/tracker con aria-label localizado distinto del placeholder. Antes solo había placeholder; SR no escuchaban el propósito. Nueva clave track.searchAria × 8 idiomas, distinta del placeholder. 930 → 931 unitarios. (NEW-D3)
[1.58.37] — 2026-05-20
fix(i18n): NEW-D1 — H1 de #/pipeline localizado en es/pt-BR/ru + 2 fugas RU corregidas. pipe.title en es ahora Pipeline de vacantes; nuevo tests/i18n-no-latin-leaks.test.mjs que también atrapó ru.contacto.title y ru.health.title. 928 → 930 unitarios. (NEW-D1)
[1.58.36] — 2026-05-20
chore(docs): v1.58.36 — limpieza completa al cerrar el ciclo v1.58.x. Sin cambios de código. (1) qa/: 3 snapshots versionados (REGRESSION-END-TO-END-v1.58.16/33/35.md) archivados en qa/archive/v158-cycle/. (2) REGRESSION-FINAL.md añade §12 con todos los invariantes v1.58.4 → v1.58.35. (3) UX-AUDIT-PROMPT.md extendido con 30 filas cerradas. (4) docs/architecture/ actualizado (FRONTEND drawer, TESTING totales 928/62/20/23). (5) CLAUDE.md gana sección “Lecciones difíciles del ciclo v1.58.x”. (6) README ×8 con nueva fila “Notificaciones 🔔” + conteo de tests corregido. Baseline sin cambios. (housekeeping)
[1.58.35] — 2026-05-20
fix(ui): v1.58.35 — el drawer de notificaciones ya no se auto-abre + nueva §18 “Notificaciones” en la ayuda. Bug v1.58.34: .notif-drawer { display: flex } ganaba contra UA [hidden] { display: none }. Fix con .notif-drawer[hidden] { display: none } explícito + sólo se abre al hacer clic en el sino. Nueva §18 en las 8 traducciones de la ayuda con la tabla de categorías. 927 → 928 unitarios. (reporte de usuario)
career-ops-ui v1.267.1 · page 6/9 · mirror of the project changelog for cvstart.org