Registro de cambios

Qué ha cambiado en SpiderHead, versión a versión. Cada entrada indica qué tipo de cambio es y si funciona hoy.

Versiones en GitHub
En desarrollo

Unreleased

Desde 3.1.065 entradas

22 de octubre de 2026

7 cambiado2 corregido
  • CambiadoFuncionaA results difference between two scans can now be attributed.#1529

    The new read-only scan-config-diff (CLI seohead scan-config-diff --before a.sqlite --after b.sqlite, MCP seo_scan_config_diff) reads both scans' recorded effective configurations from their headers — the sites are never re-read — and reports a field-by-field diff over the manifest's dotted setting paths: changed settings with both values, added, removed, an identical flag, and how many settings were compared. Identical configurations report no differences; a free-form map such as http.headers compares as one leaf, exactly as the manifest records it.

    #1529 (incidencia en GitHub)
  • CambiadoFuncionaA native crawl now measures its own reading level.#1516

    The new checks.readability module computes, offline over each page's retained content area, the sentence count, average words per sentence, the Flesch Reading Ease score (206.835 − 1.015·words/sentences − 84.6·syllables/words, English vowel-group syllable heuristic, version flesch-reading-ease.v1) and the standard band label. The four values are stored as per-URL scan fields (pages.sentence_count, avg_words_per_sentence, flesch, readability), carried into the analyzer frame under the same column names an SF export uses — so the existing READABILITY_DIFFICULT and LONG_SENTENCES checks now fire on native crawls too, with no new check IDs. A page whose content area was not retained, or holds no word with a letter, records NULL/"" — unmeasured, never a zero that would read as measured-and-easy. Text ratio and word count behavior are unchanged.

    #1516 (incidencia en GitHub)
  • CorregidoFuncionaCrawls on hosts that enforce https no longer spend a redirect hop on every http URL.#1484

    The new opt-in http.upgrade_to_https setting rewrites http URLs to https before any request — seed, sitemap seeds and discovered links alike, in both spider and list modes and in native scans: no redirect is recorded for the upgrade, the http and https spellings collapse into one page identity, and each page fetched this way carries transport_upgraded: true in its record (persisted as pages.transport_upgraded, absent in older scans reads as false). The operator opting in is the declaration that the hosts enforce transport security; a host without https answers with visible connection errors rather than a silent fallback. With the setting off, nothing changes.

    #1484 (incidencia en GitHub)
  • CambiadoFuncionaA crawl started deep can now stay in its own subtree.#1481

    The new scope.start_folder_only toggle admits only URLs at or below the start URL's path folder: a crawl started at /blog/post walks /blog/ and everything under it, and links pointing above the folder are counted as unfollowed evidence (excluded under outside_start_folder) exactly like any other scope rejection — no hand-written include patterns required. The folder is the directory the start URL sits in (a trailing-slash start keeps its own folder); a start URL at the host root is refused, because the root has no folder to stay below. The setting is recorded per scan in the run manifest like every result-affecting setting, and appears in crawl-describe-settings. With the toggle off nothing changes.

    #1481 (incidencia en GitHub)
  • CorregidoFuncionaPages that link at robots-disallowed targets are no longer silent about it.#1486

    When robots.txt disallows a linked URL and the crawl's robots policy is respect, the target is never fetched and never becomes a page row, so no target-side check can see it: the link between a page and a whole hidden section existed only in the edge list. The new ROBOTS_BLOCKED_OUTLINK finding (notice) lists, per source page, the outlinks whose destinations the policy kept out — both URLs named, internal and external edges alike, the target still never fetched. The population follows the robots policy mode: under report_only the same targets are reported (they would have been blocked), and under ignore the check skips honestly — no URL was measured against robots.txt. Crawl-list runs without retained link edges skip by name like the other link findings.

    #1486 (incidencia en GitHub)
  • CambiadoFuncionaAn image-only link now names its destination when the wrapped image carries alt text.#1518

    Links whose visible content is an image used to show an empty anchor in link evidence even when the image had a descriptive alt, so anchor-text review treated every image link as unnamed. The parser now records that alt as the link's anchor with an anchor_source: "alt" marker distinguishing alt-derived anchors from text-derived ones (absent marker = text or nothing). A link with visible text keeps its text; a link with neither stays empty and keeps feeding the no-anchor-text checks. The marker rides the LinkEdge into the scan (links.anchor_source), the links export and the per-link query views; a scan written before the field reports null there rather than a false text-derived answer.

    #1518 (incidencia en GitHub)
  • CambiadoFuncionaHrefs that cannot become fetchable link targets leave evidence instead of vanishing.#1530

    Link parsing drops an unparsable href (malformed syntax, e.g. a truncated http://[invalid) or a non-http(s) scheme (mailto:, javascript:) with no trace: the source page keeps nothing to say it points at something broken. The new opt-in crawl setting discovery.record_invalid_targets records each rejection per page — the raw href exactly as written plus the reason (unparsable_syntax / unsupported_scheme) — through the parser, the crawl record, the scan schema (pages.invalid_link_targets_json) and the analyzer frame, and the new INVALID_LINK_TARGET check turns the pages that have them into findings with the raw values as evidence. A missing href and a pure in-page #anchor are absence, not defects, and are never recorded; a measured clean page records an empty list; a crawl that ran without the setting skips the check honestly instead of reporting a clean site nobody measured. Rejected targets are data: they never enter the frontier. The setting is off by default and is recorded in the run manifest like every finding-changing setting.

    #1530 (incidencia en GitHub)
  • CambiadoFuncionaHEADING_SKIP now flags heading-order jumps in both directions, completing the#1545

    heading-sequence check: a content heading that skips a level down (H2 -> H4) and one that jumps back up past an open section (H4 -> H2) are the same defect -- the outline steps over a section that was never opened or never closed. A one-level return (H3 -> H2) closes the current section and starts a sibling, which is correct nesting and stays clean, matching the SF 24.3 axe.heading_order behaviour the check was modelled on. Evidence rows carry from/to levels and texts for both directions.

    #1545 (incidencia en GitHub)
  • CambiadoFuncionaThird-party product names now appear only where they describe compatibility: a trademark#1554

    and non-affiliation notice was added, the export analyzer is called Export Analyzer, and report reasons and docs describe what an export lacks instead of making claims about another product.

    #1554 (incidencia en GitHub)

21 de octubre de 2026

3 añadido4 cambiado3 corregido
  • CambiadoBetaEscritorio: el conjunto de URL como lista plana o como árbol de rutas.#1492

    Un conmutador de lista/árbol al final de la barra de grupos cambia el conjunto de datos entre la página plana y un árbol de rutas plegable, construido sobre las mismas filas y filtros: los hosts son los nodos superiores, las URL de directorio son sus propias carpetas-hoja y las URL de documentos cuelgan de la última carpeta. Al elegir una hoja se controla la selección compartida de la tabla, así que los detalles y los filtros se mantienen al cambiar de vista.

    #1492 (incidencia en GitHub)
  • AñadidoBetaEscritorio: modo de revisión solo de datos.#1495

    View > Data only (Ctrl+Alt+D) oculta la navegación y la barra superior en sesiones largas de revisión y deja solo los datos; la elección se mantiene por sesión, y los paneles de cada pantalla siguen respondiendo a sus propios conmutadores.

    #1495 (incidencia en GitHub)
  • CorregidoBetaLogs: aceptan time-taken en cualquier posición y diseños con un solo ident.#1534

    Los parsers de Apache ahora extraen referer, user-agent y time-taken cuando el tiempo de respuesta aparece entre el tamaño y el referer o al final de la línea, en lugar de descartar en silencio ambos campos entre comillas. La detección de formato acepta uno o dos tokens ident entre la IP del cliente y la marca de tiempo, así que el formato personalizado de nginx con un solo guion se importa en lugar de fallar por completo. El informe de importación indica las variantes aceptadas (combined-2-ident, combined-1-ident). Cubre #1534 y #1535.

    #1534 (incidencia en GitHub)
  • CambiadoBetaEscritorio: la escala de espaciado está terminada, sin márgenes fuera de escala.#1374

    Los 184 puntos de llamada restantes de setContentsMargins/setSpacing fuera de escala, repartidos en 60 archivos, pasan a la escala de tokens con una asignación que solo reduce, y el test de trinquete ahora falla ante cualquier valor fuera de escala. Antes se normalizaron Search, images, inbox, issues, logs, journal y onboarding.

    #1374 (incidencia en GitHub)
  • CambiadoBetaEscritorio: mejoras rápidas, valores TSV sin formato, proyecto en el título de la ventana

    y texto terciario con contraste AA.

    copy_tsv pega los valores almacenados, así que el marcador visible de «sin datos» nunca llega a una hoja de cálculo; el título de la ventana muestra el proyecto abierto (Project — SpiderHead); el texto terciario ahora cumple el contraste AA sobre superficies elevadas.

  • CorregidoBetaEscritorio: regiones de teclado coherentes, Return para abrir detalles y errores de

    lectura legibles.

    F6 recorre solo la navegación y la página actual; Return abre los detalles de la fila seleccionada, como prometía siempre el menú de la fila; los errores de lectura en la barra de estado indican la operación (tabla de URL, parámetros de rastreo) en lugar del identificador de solicitud sin procesar.

  • CambiadoBetaEscritorio: el menú View se vincula a los paneles propios de la pantalla actual.

    Una pantalla puede exponer panel_actions(), tríos (título, si está visible, alternar), y el menú View construye su sección de paneles a partir de la pantalla al mostrarla. La pantalla de URL ofrece su resumen de ejecución y el modo solo tabla; los elementos de auditoría heredados siguen en su propia página.

  • CorregidoBetaEscritorio: que los ticks de actividad dejen de llenar los logs de ventanas cerradas.

    La señal global de actividad seguía llamando a widgets BusyIndicator ya eliminados; las ventanas cerradas ahora permanecen en silencio.

  • AñadidoBetaEscritorio: las pestañas del modo simple se pueden ocultar y restaurar.

    Menú contextual de la barra de pestañas: ocultar una pestaña, restaurar las ocultas o mostrarlas todas; la elección se mantiene. La primera pestaña siempre permanece, la última pestaña visible no se puede ocultar y una pestaña oculta reaparece cuando Overview entra en ella.

  • AñadidoBetaEscritorio: estados del modo simple, barra de marca y capturas sin conexión.

    Paneles de estado con acciones: sin resultados (borrar búsqueda / mostrar todo), fallido (reintentar / mostrar registro), núcleo no encontrado (abrir ajustes); un aviso de detención cuenta las URL rastreadas y en cola. La barra de herramientas lleva la marca de la araña, y el contador de errores es una insignia.

20 de octubre de 2026

1 añadido3 cambiado
  • CambiadoBetaEl paquete de la CLI seohead se divide en módulos por dominio.#1514

    cli/_shared.py contiene los registros de comandos y los auxiliares de entrada; checks_cmds, project_cmds, scan_cmds, crawl_cmds, sources_cmds, reports_cmds y misc_cmds contienen cada uno su parte del antiguo mapeo de argumentos con nombre (kwarg), de las banderas de argparse y de los casos especiales del despacho principal de cli/__init__.py. La superficie de importación publicada no cambia y el módulo se reduce de 4506 a 513 líneas; la salida de --help sigue siendo idéntica byte a byte para cada comando.

    #1514 (incidencia en GitHub)
  • CambiadoBetaLos manejadores de MCP pasan a un paquete propio.#1514

    Los manejadores del servidor ahora viven en seohead/mcp/handlers/, divididos por dominio: proyectos, tráfico, logs, fuentes, contenido, semántica, flujo de trabajo, escaneos conservados, evidencias y exportación BI, entorno y catálogo. La documentación y las referencias a rutas de código siguen la nueva estructura.

    #1514 (incidencia en GitHub)
  • CambiadoBetaTabla de URL: selección de varias filas con copia TSV de la selección.#1347

    Pulido de la tabla de URL de #1347: selecciona varias filas y copia exactamente la selección como TSV.

    #1347 (incidencia en GitHub)
  • AñadidoBetaControl del ritmo de rastreo en vivo: núcleo (trabajo en curso).#1360

    El núcleo que permite cambiar la velocidad de rastreo mientras se ejecuta un escaneo (#1360); la conexión con Escritorio llega después.

    #1360 (incidencia en GitHub)
Días anteriores (4)Show all

14 de octubre de 2026

3 cambiado
  • CambiadoBetaEscritorio: progreso del escaneo, límite de URL, botón de parada y motivos de#1358

    finalización.

    Completadas, en cola, velocidad y tiempo restante estimado, así como el límite de URL solicitado, se muestran en la lista de escaneos, en los detalles del escaneo y en la tarjeta de navegación. El control de la barra superior se llama Stop scan en lugar de mostrar un id de ejecución, se actualiza sin parpadeos y se oculta cuando la ejecución termina; las ejecuciones finalizadas indican por qué acabaron (límite de URL, de solicitudes o de tiempo, errores o disco).

    #1358 (incidencia en GitHub)
  • CambiadoBetaEscritorio: un solo sistema de botones, márgenes de página estándar y sin chips de

    funciones no disponibles.

    Un único sistema de botones en todas las pantallas, márgenes de página estándar, y se eliminan los chips de las funciones no disponibles.

  • CambiadoBetaEscritorio: el generador de redirecciones y el editor de snippets pasan a una sección de

    Herramientas.

    Methods contiene solo el catálogo de métodos y muestra el escaneo seleccionado al abrirse; el editor de snippets preselecciona el contexto del escaneo seleccionado.

13 de octubre de 2026

3 cambiado
  • CambiadoFuncionaEscritorio Crawler: pestañas de detalle de URL (enlaces entrantes, salientes, recursos,#1349

    snippet, fuente guardada, cabeceras HTTP) sobre el archivo del rastreo, con filtros por pestaña y recuentos, un resumen más completo con directivas, un selector de columnas por pestaña conectado a las columnas de exportación, ordenación por encabezado, menú contextual y navegación por teclado; New scan puede guardar sus ajustes como un perfil de rastreo con nombre.

    #1349 (incidencia en GitHub)
  • CambiadoFuncionaEscritorio: superficies sin conectar: la sección Link graph lee totales de nodos, aristas#1347

    y páginas huérfanas, y una página…

    Escritorio: superficies sin conectar: la sección Link graph lee los totales de nodos, aristas y páginas huérfanas, y una tabla paginada de nodos desde el comando del núcleo scan-graph, en lugar de un marcador de posición. Issues enumera los grupos de comprobaciones más grandes a partir de los contadores por comprobación del núcleo, y la tabla de URL muestra y ordena la columna Inlinks (con una nota alternativa cuando un escaneo no conservó observaciones de enlaces); la columna Issue count, que nunca podía medirse, ya no se ofrece. Exportación e informes ejecutan el comando del núcleo scan-export para páginas o hallazgos en CSV, XLSX, JSON o XML en la carpeta elegida; se eliminan los conjuntos de datos de comparación y de tareas, la columna de marcador y el historial de exportación que el núcleo no puede respaldar. Los ajustes guardados pero aún no aplicados aparecen ahora desactivados de forma visible, con el motivo al pasar el cursor. El diálogo de configuración del rastreo enumera una sola vez, en solo lectura, los parámetros sin editor validado, en lugar de mezclarlos con la lista del editor, y el campo «Why this scan» de New scan explica por qué está vacío.

    #1347 (incidencia en GitHub)
  • CambiadoFuncionaEscritorio: superficies sin conectar: la sección Crawler ejecuta un rastreo puntual sin#1347

    proyecto.

    Escritorio: superficies sin conectar: la sección Crawler ejecuta ahora un rastreo puntual sin proyecto. El campo de dirección, el conmutador Site/List/Sitemap, el límite de URL, Start/Stop, las pestañas de comprobaciones, la búsqueda por dirección, los contadores de la vista general, el panel de detalles y la exportación CSV/XLSX están conectados a los comandos del núcleo crawl-site --scan-out y scan-url-query; la barra de estado muestra las cifras propias del núcleo de velocidad, rastreadas y restantes. Nada se inicia al abrir la pantalla, y el resultado temporal se elimina al pulsar Clear, en el siguiente rastreo y al cerrar la aplicación. Las entradas del menú de rastreo rápido abren la sección. Se elimina la insignia «Unavailable in this core version» de la barra superior. Compare ya no se abre en estado de error tras leer un proyecto: una comparación vacía es un aviso neutral para elegir dos escaneos, y solo un fallo real muestra el estado no disponible.

    #1347 (incidencia en GitHub)

12 de octubre de 2026

8 añadido10 cambiado2 corregido
  • CorregidoFuncionaCorrige la compatibilidad de la configuración de escaneo nativo entre actualizaciones y#1344

    reversiones. Se conservan la cabecera y la huella existentes, las nuevas opciones efectivas se guardan en un contexto versionado, y el comportamiento heredado de parámetros de seguimiento se mantiene cuando falta ese contexto. Al reanudar se valida el conjunto completo de ajustes efectivos y se rechazan los artefactos no compatibles o inconsistentes.

    #1344 (incidencia en GitHub)
  • CorregidoFuncionaCorrige la detección de RDFa conservado para que las IRI de propiedad relativas y los#1344

    hosts no relacionados no establezcan marcado Schema.org. Se conservan las IRI de vocabulario absolutas y los prefijos reconocidos, y las pruebas de plazo de búsqueda siguen acotadas con patrones de datos de prueba poco costosos.

    #1344 (incidencia en GitHub)
  • CambiadoFuncionaLas pestañas compactas de ajustes del proyecto se mantienen dentro de la ventana, y los#1315

    ajustes adicionales se muestran en un menú de desbordamiento. Se oculta el selector de programación redundante cuando solo está disponible el sitio principal, manteniendo la selección entre sitios vinculados en ambos tamaños de ventana. - Se muestra la vista previa de User-Agent personalizado solo cuando su valor está disponible; un nombre de preajuste no se presenta como la cabecera realmente enviada. Se conservan los límites de retardo configurados del programador. - Se reevalúa la creación de tareas de propietario tras actualizar el proyecto, y las ejecuciones de competidores compatibles validadas por el núcleo se conservan entre revisiones de checklist no relacionadas. La confirmación y las comprobaciones de la revisión actual siguen siendo obligatorias para las escrituras. - La verificación de bots se desactiva hasta que haya registros de proyecto conservados, se admiten las llamadas habituales de Qt a modelos de tabla, y los totales guardados de incidencias se muestran por separado de las muestras acotadas de URL y de las comprobaciones no medidas. - Las fuentes incluidas se registran una vez por aplicación, en lugar de duplicarse en cada cambio de tema.

    #1315 (incidencia en GitHub)
  • AñadidoFuncionaAñade gestión de credenciales de proveedor solo de escritura por el canal stdin de la CLI#1343

    local, con consentimiento OAuth de GSC explícito…

    Añade gestión de credenciales de proveedor solo de escritura a través del canal stdin de la CLI local, ciclo de vida explícito del consentimiento OAuth de GSC y descubrimiento de recursos de cuenta solo en vista previa; la selección de proveedor y las escrituras de credenciales MCP quedan sujetas a decisiones explícitas del propietario. - Añade hallazgos acotados de URL Inspection a la salida de SF vinculada a un proyecto, tras la opción explícita --gsc-inspect, con contabilidad local de cuota por propiedad y un historial de inspecciones conservado y con lista de permitidos. SF también une el historial medido de URL de GSC, GA4, Metrika y Cloudflare sin llamadas implícitas a proveedores; los hallazgos por URL registrados entran en el flujo ordinario de incidencias de la auditoría, mientras que la cobertura ausente o parcial se indica de forma explícita. - Añade instantáneas diarias agregadas por URL de Cloudflare, importación explícita de Enterprise Logpull, importación de NDJSON de Logpush aportado por el usuario a través del almacén local de logs, y lecturas de solo lectura y opcionales de los ajustes de IA, de los conjuntos de reglas de redirección/WAF y de los trabajos de Logpush. Una captura de Instant Logs, confirmada por separado y sujeta al plan, usa una sesión WebSocket breve y acotada y conserva solo un prefijo local limitado; la ruta no toca las sesiones existentes e informa del vencimiento por inactividad documentado por Cloudflare, porque la API Edge no ofrece endpoint de parada. Los flujos de destino de Logpush siguen siendo propiedad del cliente y no se ingieren. - Añade una operación explícita de backlinks JSON-RPC actual de Moz, manteniendo las métricas de URL heredadas como opción predeterminada, y deja los recibos de gasto inciertos como null en los informes de registro. - Añade un lector acotado de resumen de artefactos de PageSpeed que valida la propiedad y devuelve solo campos de Lighthouse incluidos en la lista de permitidos.

    #1343 (incidencia en GitHub)
  • CambiadoFuncionaLos perfiles de rastreo con nombre se pueden inspeccionar como JSON validado, seleccionar#1299

    con seo_crawl_site…

    Los perfiles de rastreo con nombre se pueden inspeccionar como JSON validado, seleccionar mediante seo_crawl_site y asignar como predeterminados del proyecto, con las anulaciones de rastreo del proyecto superpuestas encima. - El progreso del rastreo estima el tiempo para la frontera conocida actual y lo indica por separado de la duración total del rastreo; los destinos de rastreo normalizan por defecto los parámetros utm_* y fbclid. - Los escaneos nativos activos de proyecto aceptan solicitudes puntuales de pausa y detención por id de ejecución y checkpoint, a través de la ruta de recuperación SQLite existente. - La autenticación HTTP Basic/Digest vinculada a un host y la negociación opcional de respuestas zstd usan referencias a variables de entorno, confirmación explícita, autenticación solo por HTTPS y presupuestos de solicitudes. Los resultados del rastreo incluyen estimaciones acotadas de carga y conservan como null el tamaño de disco desconocido.

    #1299 (incidencia en GitHub)
  • AñadidoFuncionaAñade un resumen operativo del estado del proyecto: progreso de los colectores activos,#1291

    integridad del último escaneo…

    Añade un resumen operativo del estado del proyecto con el progreso de los colectores activos, la integridad del último escaneo completado, el estado de las carpetas, las tareas abiertas del proyecto principal, la última actividad registrada de agentes y el tamaño persistido del directorio de escaneos; el estado de conexión sigue como desconocido sin un heartbeat en vivo.

    #1291 (incidencia en GitHub)
  • AñadidoFuncionaAñade un contrato de información del núcleo legible por máquina, con revisión y hora de#979

    compilación verificadas, herramientas CLI y MCP compatibles y compatibilidad exacta por revisión con Escritorio; añade un comando doctor general de solo lectura y una herramienta MCP para comprobar los requisitos previos locales. seohead --version muestra la versión del paquete. - Añade lecturas condicionales opacas y sensibles a la revisión para project-observe y project-activity; añade comprobaciones de versiones que requieren consentimiento y descargas de wheel/fuente con verificación de checksum, con progreso, cancelación y sin instalación automática.

    #979 (incidencia en GitHub)
  • AñadidoFuncionaAñade estimaciones de comprobación previa de las fases de pago e historial de estado por#1298

    fase a los proyectos de semantic-core. - Admite vistas previas de importación CSV/XLSX con mapeo, exportaciones acotadas por alcance, lecturas paginadas de clústeres, selecciones de landing page auditadas y perspectivas locales basadas en evidencias.

    #1298 (incidencia en GitHub)
  • AñadidoFuncionaAcciones de página y preajustes acotados, activables por proyecto, en los rastreos#1302

    renderizados; diferencias de versión sin procesar frente a renderizada conservadas…

    Se añadieron acciones de página y preajustes acotados, activables por proyecto, a los rastreos renderizados; se conservan las diferencias entre elementos sin procesar y renderizados y los fallos de red del navegador. Se exponen hallazgos de desbordamiento móvil, tamaño de texto y tamaño de objetivo a partir de los diseños renderizados capturados. Se añadió captura de la primera pantalla y metadatos explícitos de representación del DOM.

    #1302 (incidencia en GitHub)
  • AñadidoFuncionaSe añadieron los estados exactos checks_run, checks_skipped, checks_disabled y los#1296

    totales del registro a las evidencias de escaneos guardados…

    Se añadieron los estados exactos checks_run, checks_skipped, checks_disabled y los totales del registro a las evidencias de escaneos de proyecto guardados. Los recuentos evaluados y omitidos siguen siendo disjuntos, y la cobertura de auditoría ausente se informa como no disponible. - Los escaneos guardados exponen ventanas acotadas de HTML estático y renderizado con identidad de escaneo y de documento, hashes del cuerpo sin procesar y del texto decodificado, y páginas de hallazgos por URL exacta a través de los manejadores compartidos de CLI y MCP. El detalle de URL incluye una ventana acotada del HTML fuente; la evidencia no disponible o ambigua se mantiene explícita. La comparación de cuerpos admite pares estático/renderizado además de pares entre escaneos. - El estado del escaneo informa de la integridad, del escaneo afectado, de la disponibilidad de checkpoints y de recuentos de daños anulables. Los archivos portables de proyecto pueden omitir todos los cuerpos HTML, omitir los cuerpos de más de 30 o 90 días, o conservar solo los N escaneos reconocidos más recientes, manteniendo las tablas de evidencias.

    #1296 (incidencia en GitHub)
  • CambiadoFuncionaConsultas de URL de escaneos guardados ampliadas con recuentos de enlaces conservados,#1295

    filtros de título, canonical, hreflang y sitemap, y facetas según la fuente. Las mediciones ausentes de enlaces, sitemap, hreflang o auditoría siguen como no disponibles en lugar de aparecer como cero. - Se añadieron contadores de severidad por escaneo completo y por comprobación a partir del resumen de auditoría guardado, incluidos los estados explícitos de comprobación disparada, silenciosa, omitida, desactivada y no disponible. - Se persiste un índice de profundidad de clic mínima reconstruible al terminar una captura scan.v2 o un reanálisis sin conexión; los archivos de escaneo anteriores siguen derivando la profundidad de su grafo de enlaces conservado dentro del presupuesto de consulta. - Se añadieron filtros de recursos por tipo y URL vinculados al documento de origen, recuentos por aparición y por tipo, estados de bytes conservados y agregados de bloques y pesos en la evidencia de recursos guardada; las declaraciones no disponibles y los pesos de descarga parciales siguen explícitos. - Se capturan en scan.v2 los tiempos de TCP/conexión, TLS, espera de cabeceras de respuesta y descarga del cuerpo de HTTPX cuando el transporte emite eventos de traza. DNS sigue no disponible porque HTTPX no expone un evento de resolución separado; su tiempo puede estar incluido en la conexión. Se añadió headers-analyze sin conexión para las cabeceras y la evidencia de fases redactadas guardadas. - Se añadió una lectura de árbol de directorios por CLI/MCP con agregación SQLite temporal, con profundidad, número de hijos, número de nodos y bytes de salida acotados. Las lecturas de ruta más corta existentes siguen disponibles mediante scan-link-inspect --view path. - Se añadió scan-link-inspect --view links --preset inlinks|broken_links para vistas con nombre de enlaces internos entrantes y de destinos salientes rotos. - La finalización nativa de scan.v2 y el reanálisis sin conexión intentan ahora una proyección indexada opcional de consulta de URL vinculada a la fuente, para recuentos y tipos de recursos por página, marcas de título duplicado, cobertura y facetas sin filtrar. Las lecturas solo la aceptan para un escaneo terminado con UUID de escaneo, revisión de evidencia, capacidades y URL de inicio coincidentes; reencolar invalida su publicación. Los escaneos anteriores mantienen la lectura alternativa acotada y de solo lectura, sin migración de scan.v1. En el accesorio sintético de un escaneo terminado de 1M de páginas con HTML e imágenes compartidas, el productor real de la proyección terminó en 6,36 s con un pico de 400,7 MB de RSS. Las medianas de cinco ejecuciones fueron de 5,23–43,38 ms para páginas con columnas de recursos, 60,81 ms para el filtro de imágenes y 5,38 ms para todas las facetas, dentro de los presupuestos de 200/300 ms; 100 filas de imágenes fueron exactas. Esto valida el rendimiento de consultas guardadas sintéticas, no un rastreo real de 1M de URL. Los enlaces entrantes y las facetas de sitemap siguieron explícitamente no disponibles, así que la respuesta de facetas fue parcial.

    #1295 (incidencia en GitHub)
  • CambiadoFuncionaEl checklist de proyecto v4 incluye responsables, criterios de aceptación, enlaces a#1294

    incidencias y métodos, límites de URL de competidores…

    El checklist de proyecto v4 incluye responsables, criterios de aceptación, enlaces a incidencias y métodos, límites acotados de URL de competidores y comentarios de tareas atribuidos y de solo adición, manteniendo la lectura de formatos de cobertura anteriores. - Al aceptar un objetivo del buzón se crea su tarea personalizada estable del checklist, con el objetivo original como descripción; la aceptación sigue sin ejecutar ni completar la tarea. - Las vistas de tareas e informes muestran estados de medición honestos por tarea para las URL afectadas, así como KPIs de tareas personalizadas; los recuentos siguen no disponibles cuando la evidencia conservada no enumera las URL afectadas.

    #1294 (incidencia en GitHub)
  • CambiadoFuncionaLos informes Markdown, DOCX y XLSX vinculados a un proyecto incluyen recuentos de tareas#1297

    personalizadas, asignación y criterios de aceptación…

    Los informes Markdown, DOCX y XLSX vinculados a un proyecto incluyen recuentos de tareas personalizadas, campos de asignación y de criterios de aceptación, y la evidencia anulable de URL afectadas con su estado de medición.

    #1297 (incidencia en GitHub)
  • AñadidoFuncionaAñade metadatos de categoría y de reconocimiento de proyecto con paginación por#1312

    desplazamiento al catálogo de herramientas MCP, y un lote acotado de comprobación de URL para listas explícitas o páginas de escaneos conservados. - Añade optimización automática de calidad de imagen guiada por SSIM, eliminación explícita de EXIF e informes de optimización de imágenes de escaneos conservados; añade salida CSV de WordPress Redirection con análisis local de cadenas y bucles. - Muestra las banderas heredadas de profundidad y retardo de rastreo en la ayuda y mantiene su comportamiento de compatibilidad.

    #1312 (incidencia en GitHub)
  • AñadidoFuncionaLecturas de flujo compare.v2 acotadas con comprobaciones de integridad, ordenación y#1300

    filtrado por URL; genera un resumen Markdown acotado…

    Añade lecturas de flujo compare.v2 acotadas con comprobaciones de integridad, ordenación y filtrado por URL, y genera un resumen Markdown acotado y tarjetas antes/después por URL exacta que conservan las observaciones ausentes como no recomprobadas. - Amplía el historial guardado de URL con datos de página y deltas entre escaneos adyacentes; las observaciones no disponibles o ausentes siguen sin ser comparables. - Persiste checkpoints de comparación e instantáneas de progreso para reanudar con una entrada exacta, reutiliza los paquetes completados y verificados como aciertos de caché, y añade cortes por segmento principal en cada cambio y evidencia de códigos de respuesta de enlaces externos conservada.

    #1300 (incidencia en GitHub)
  • CambiadoFuncionaAmplía el lector de datos estructurados conservados por URL exacta con JSON-LD,#1304

    Microdata, RDFa…

    Amplía el lector de datos estructurados conservados por URL exacta con JSON-LD, Microdata y RDFa acotados, evidencia de idioma, linaje de fuentes y validación local sin conexión de Schema.org.

    #1304 (incidencia en GitHub)
  • CambiadoFuncionaLa búsqueda de contenido conservada informa de ocurrencias acotadas con desplazamientos#1301

    de caracteres en el texto fuente, líneas numeradas desde uno, navegación de coincidencias por documento y ventanas opcionales redactadas de seis líneas. El filtrado por URL exacta se ejecuta antes de que SQLite ordene los documentos conservados. Los recuentos completos de coincidencias siguen visibles cuando el límite de 10 000 desplazamientos o de 64 KiB trunca las ocurrencias devueltas, y la cobertura es parcial. Las búsquedas con expresiones regulares no están disponibles cuando no se puede imponer un plazo de reloj de pared; los cuerpos no disponibles siguen siendo desconocidos, nunca ausentes. - Los paquetes de búsqueda indexados están limitados a 512 MiB; al alcanzar el límite se publica un paquete explícitamente incompleto, con su cobertura medida y su límite de bytes. - Se añadió una ruta sin conexión de muestra de extracción personalizada para HTML aportado por el usuario. Su URL opcional es solo una etiqueta y no provoca ninguna descarga; la obtención de URL en vivo sigue siendo una decisión del propietario.

    #1301 (incidencia en GitHub)
  • CambiadoFuncionaImporta filas CSV de edición de snippets en tareas de revisión sin aplicar, mide la#1010

    tipografía local según el perfil definido por el llamante y añade extractos de consulta de escaneos guardados seleccionados explícitamente, con linaje de documento; no se infiere ningún umbral de motor de búsqueda ni afirmación de renderizado.

    #1010 (incidencia en GitHub)
  • CambiadoFuncionaLos rastreos nativos almacenados comparan cuerpos de respuesta conservados con un#1013

    conjunto acotado de familias reconocibles de Content-Type…

    Los rastreos nativos almacenados comparan los cuerpos de respuesta conservados con un conjunto acotado de familias reconocibles de Content-Type; los cuerpos no disponibles, sobredimensionados o ambiguos siguen sin medirse de forma explícita.

    #1013 (incidencia en GitHub)
  • CambiadoFuncionaEl análisis nativo de imágenes conservadas informa de declaraciones de tamaño ausentes o#1303

    no válidas y de texto alternativo vacío informativo o malformado, y mantiene el alt="" decorativo válido. Los atributos alt ausentes literales siguen siendo hallazgos con un nombre ARIA; las imágenes decorativas visibles todavía necesitan tamaños. - Los hallazgos de imagen conservan el alcance de origen, destino y estado, el motivo, el documento y las ubicaciones ordinales acotadas. Los cuerpos ausentes conservan los hechos positivos conocidos de recuento de páginas, sin inventar una URL de imagen ni una respuesta de recurso. Los errores de respuesta de imagen y los umbrales de bytes conservan estado y motivo. - La selección de imágenes resuelve las páginas de origen tras reabrir. La evidencia de recursos nombra junto a los documentos de origen las filas conservadas de obtención y declaración. La identidad de imagen nativa incluye la página de origen y el alcance, evitando deliberadamente colapsar entre páginas, y migrando las huellas nativas de imagen anteriores. Los hallazgos heredados sin página de origen mantienen su identidad anterior; los elementos repetidos conservan recuentos exactos y muestras acotadas de ubicación. - La tienda sintética conserva los defectos originales y 15 controles, y añade casos de alt vacío informativo y de tamaño ausente en productos existentes sin cambiar los recuentos del rastreo.

    #1303 (incidencia en GitHub)

11 de octubre de 2026

16 cambiado
  • CambiadoFuncionaEjecuta la suite completa del toolkit una sola vez en Python 3.15 en lugar de una matriz

    de versiones anteriores, conservando…

    Ejecuta la suite completa del toolkit una sola vez en Python 3.15, en lugar de una matriz de versiones anteriores, conservando cuatro grupos de pruebas verificados y la cobertura combinada. Usa la misma versión estable de Python para los arranques de CI y de compilación de releases.

  • CambiadoFuncionaConsolida las comprobaciones de auditoría conservadas y las mejoras de escritorio nativo.

    Preserva los ajustes de presupuesto de recursos sin cambiar la cabecera de escaneo congelada, conserva el reanálisis y la reanudación seguros sin conexión, y comparte los componentes nativos de ajustes del proyecto, los tokens de tema y las fuentes incluidas. Elimina los insumos de diseño privados del árbol distribuido. - Vincula las comprobaciones de remediación a la política de activos efectiva validada, conservando la cabecera de escaneo original y los bytes de origen.

  • CambiadoFuncionaRehace Project settings (Schedule y Crawl) con componentes nativos de lienzo compartidos,#1323

    fuentes Roboto sin conexión…

    Rehace Project settings (Schedule y Crawl) con componentes nativos de lienzo compartidos, fuentes Roboto y Material Symbols sin conexión y un diseño de una sola columna a 800 px. - Usa inglés en toda la interfaz de la aplicación, conserva el comando de programación existente y los contratos de documentos, y muestra solo datos de programación respaldados por el núcleo. - Conserva las identidades y alias de los espacios de trabajo mientras Project settings está abierto, e impide guardar varias veces mientras el núcleo está respondiendo.

    #1323 (incidencia en GitHub)
  • CambiadoFuncionaEscritorio: los ajustes del proyecto ganan una pestaña Schedule (días laborables, días#1322

    del mes, ventana de ejecución, zona horaria…

    Los ajustes del proyecto de escritorio ganan una pestaña Schedule (días laborables, días del mes, ventana de ejecución, zona horaria, competidores) y una pestaña Crawl (modo de rastreo, preajuste o cadena personalizada de User-Agent, pausa entre solicitudes, presupuesto de URL, SpiderHeadBot o un user agent personalizado); ambas leen y escriben el proyecto a través del núcleo, y la vista general del proyecto muestra la próxima y la última ejecución programada. Un modo --tray ejecuta los escaneos vencidos del núcleo y mantiene el Mac despierto solo mientras se ejecuta un escaneo.

    #1322 (incidencia en GitHub)
  • CambiadoFuncionaLas auditorías nativas exponen el marcado del head que bloquea el renderizado a partir#1303

    del HTML conservado completo, sin cambiar…

    Las auditorías nativas exponen ahora el marcado del head que bloquea el renderizado a partir del HTML conservado completo, sin cambiar el esquema congelado scan.v1. Los cuerpos incompletos, ausentes o limitados por presupuesto siguen no disponibles. Se reutilizan la detección existente de recursos del head y la entrada de extracción personalizada de SF. - Añade presupuestos nativos configurables de navegación observada y de bytes por recurso individual, señales de caché y entrega de fuentes, heurísticas de minificación y de scripts heredados, y duplicados exactos de scripts en la misma página a partir de la evidencia scan.v2 conservada. Los datos no descargados y las cargas de tiempo de ejecución incompletas siguen siendo explícitos; las declaraciones responsivas no se suman como peso de ejecución. Los límites inferiores solo de HTML, los recuentos escalares de cobertura, las muestras de fuentes y los resúmenes de origen siguen explícitos y acotados. - Recoge la cobertura precisa acotada de JS/CSS de Chromium en renders solicitados, conserva resúmenes de uso UTF-16 y hallazgos renderizados de dimensionado de imágenes, y los lee tras reabrir o en reanálisis sin conexión. Los motores no compatibles y las mediciones ausentes no se convierten en resultados limpios. - Acepta JSON de Lighthouse acotado y coincidente por URL para el descubrimiento de LCP, árboles de dependencias, responsables de cambios de diseño, entrega de imágenes, reflujo forzado y hallazgos de ejecución de scripts, con procedencia de la captura y hashes de entrada. No se añade ningún proceso de Lighthouse, proveedor de pago ni inferencia de Core Web Vitals de campo. Actualiza el registro, la cobertura de SF y la documentación de referencia generada. - Mantiene los valores exactos de los umbrales de activos adicionales fuera de la cabecera de escaneo nativa congelada y los guarda en un contexto de ejecución validado y versionado. La reanudación compara estos valores por separado, y el reanálisis sin conexión los restaura desde la evidencia conservada; los lectores ligeros anteriores pueden seguir inspeccionando la forma sin cambios de la configuración de la cabecera.

    #1303 (incidencia en GitHub)
  • CambiadoFuncionaConserva la evidencia AMP estática y de accesibilidad vinculada al documento en las filas#1304

    de contexto de escaneo existentes, preservando el esquema SQL congelado scan.v1. Los hallazgos AMP estructurales inspeccionan el doctype original, head/body, el charset UTF-8, el viewport, el script de ejecución y las declaraciones de boilerplate; los destinos AMP emparejados sin marcador de raíz AMP se identifican por separado. Las reglas completas del validador AMP siguen no disponibles a la espera de una decisión de licencia. - Inicia hallazgos de accesibilidad para el idioma del documento, las etiquetas de formularios, las alternativas de imagen, los saltos de encabezado y el landmark principal. Los hallazgos conservan ejemplos acotados y recuentos completos de ocurrencias. El contraste calculado y las reglas renderizadas de axe-core siguen sin medirse. - Valida los sujetos y propiedades de Schema.org Microdata y RDFa comunes con el vocabulario incluido y las reglas existentes de resultados enriquecidos. Los errores, advertencias y propiedades obligatorias ausentes conservados por URL se convierten en hallazgos nativos. Las construcciones RDFa no compatibles son evidencia parcial explícita, no un resultado de validación limpio. - Sirve los árboles JSON-LD parseados junto con el origen de cada bloque, su posición y los errores de sintaxis en scan-structured-blocks; limita los árboles de propiedades anchos y expone ese límite. Lee el último documento de una URL solicitada y de una representación sin cambiar su escaneo. - Conserva la evidencia estructurada parcial o no disponible sin ocultar los errores hermanos confirmados. Resuelve las identidades JSON-LD compatibles frente a la misma base de documento que el marcado HTML, preservando el JSON fuente; rechaza los bloques JSON escalares o vacíos como grafos válidos y comparte la selección normalizada de etiquetas JSON-LD vivas entre el parser y las proyecciones servidas.

    #1304 (incidencia en GitHub)
  • CambiadoFuncionaConserva los atributos canonical y de paginación sin procesar como contexto de documento#1305

    versionado, sin cambiar el SQL congelado del escaneo. Los enlaces canonical con atributos hreflang/lang/media/type no compatibles, las anotaciones mal formadas y las declaraciones entre hosts o protocolos distintos generan ahora hallazgos vinculados a la evidencia; las palabras clave de relación bien formadas pero desconocidas siguen sin clasificar. - Amplía las sondas acotadas de destino del mismo host a la paginación y conserva observaciones medidas de noindex/canonical. Las cadenas canonical nativas y los hallazgos de noindex en canonical/hreflang pueden usar sondas; las sondas heredadas solo de estado siguen siendo legibles y sin medir para las directivas HTML. - Juzga las cadenas de paginación nativas opacas en busca de contradicciones recíprocas explícitas de next/prev, conservando las reglas numeradas y de paso y los estados sin juzgar con nombre. Selecciona las URL de hallazgos guardados, incluidos los miembros de grupos, mediante scan-url-query con tablas SQLite temporales y evidencia audit.v2 en streaming. - Mantiene los tokens de relación Unicode y con signos de puntuación sin clasificar, normaliza las autoridades canonical IDN y de puerto por defecto equivalentes, y preserva las rutas exactas de destino de paginación nativa. Los tokens de página mixtos ilegibles siguen sin juzgar; el defecto de paginación de la tienda se recupera aunque la página uno no tenga número en su URL. - Renderiza las anotaciones next/prev declaradas de la tienda de prueba para que su verdad de referencia de paginación D41 se sirva y pueda validarse mediante captura nativa.

    #1305 (incidencia en GitHub)
  • CambiadoFuncionaLos logs de servidor conservan ahora totales exactos de IP de bots respaldados en disco#1311

    en lugar de una muestra limitada, con límites…

    Los logs de servidor conservan ahora totales exactos de IP de bots respaldados en disco en lugar de una muestra limitada, con registros acotados por IP, visitas, última visita y filtros por subred. La verificación DNS explícita comprueba cada IP seleccionada por separado, registra evidencia PTR y de resolución directa, admite IPv6 y conserva los resultados no disponibles o con tiempo agotado como no comprobados. Las cachés locales caducan tras una hora; las lecturas nunca lanzan consultas DNS. - Se añadieron la importación local de logs del proyecto, el resumen paginado, la evidencia de bots y los comandos de unión con escaneos nativos, a través de los manejadores compartidos de CLI/MCP. Los artefactos de logs separados conservan particiones por fecha y la cobertura y procedencia de las fuentes sin cambiar los esquemas congelados de escaneo. Las evidencias incompletas o ausentes retienen las conclusiones de ausencia. Las pantallas de logs de Escritorio siguen siendo un seguimiento de presentación aparte.

    #1311 (incidencia en GitHub)
  • CambiadoFuncionaLas auditorías nativas conservadas agrupan ahora los enlaces internos rotos por destino#1306

    observado, con evidencia de origen y texto ancla, registran cadenas y bucles de redirección con estados por salto, distinguen las búsquedas internas basadas en ruta y los anclajes vacíos, y exponen los resultados capturados de enlaces externos sin respuesta. Las comprobaciones de coherencia de sitemap y robots.txt usan la pertenencia conservada y la evidencia de respuesta sin nuevas descargas en vivo; la evidencia ausente o parcial sigue explícita. - Se añadió un grafo de enlaces acotado de escaneos guardados, con filtros por posición, sección y vecindario local, agregación por sección y cambios de aristas entre escaneos. El reanálisis sin conexión rellena las posiciones con lotes derivados reanudables y notifica la evidencia no clasificada en la inspección de enlaces y en el estado del escaneo, preservando el esquema congelado scan.v1. - Se añadió generación local de sitemap XML a partir de páginas 200 canonical e indexables conservadas, con lastmod observado, exclusiones, división por protocolo, índice de sitemap y sitemap de imágenes opcional. CLI y MCP comparten las mismas implementaciones; la publicación de la salida exige un directorio local nuevo y nunca despliega archivos. - Conserva los destinos de descubrimiento ausentes registrados en el momento de la captura cuando un sitemap o un procesamiento posterior de semillas añade la URL al catálogo conservado. La evidencia explicada de no resuelto o excluido permanece inmutable, mientras que los destinos conocidos declarados y las discrepancias de identidad no nulas siguen siendo inválidos. - El sitemap de imágenes excluye las respuestas de recurso no-200 conocidas aunque el recurso no se haya guardado como página rastreada, y marca las respuestas de imagen no medidas como cobertura parcial.

    #1306 (incidencia en GitHub)
  • CambiadoFuncionaProtege las llamadas de producción de Google DataForSEO antes de construir el cliente,#1310

    expone cotizaciones sin conexión a partir de precios de proveedor proporcionados, tiene en cuenta la profundidad de SERP y los cargos por operadores de búsqueda, y aplica techos conocidos en USD por llamada antes del transporte. Amplía las operaciones acotadas del índice de backlinks y registra los costes ausentes o las formas de respuesta mal formadas como recibos inciertos. Los límites de moneda por proyecto y por mes siguen pendientes de decisión del propietario. - Fusiona la evidencia explícita de origen e importación de backlinks en instantáneas privadas de historial local, con todas las observaciones de tokens rel, anclas, dominios de referencia, filtros y señales transparentes de revisión de spam. Añade rutas CLI/MCP de perfil y de exportación de disavow revisada, sin envíos automáticos. - Añade avisos de revisión de tokens rel mixtos y de divulgación patrocinada de enlaces salientes a partir de la evidencia nativa conservada, conservando el contexto no disponible, recuentos nulos para poblaciones de HTML enteramente no analizadas, y las clases sponsored/ugc/nofollow en informes y en las comprobaciones de donantes, sin cambiar el esquema congelado de escaneos conservados.

    #1310 (incidencia en GitHub)
  • CambiadoFuncionaLas comprobaciones nativas de DOM y de duplicados leen ahora el documento conservado#1307

    seleccionado de cada página por URL exacta, con linaje verificado de respuesta y cuerpo. La retención deshabilitada, los cuerpos ausentes, no válidos o que superan el presupuesto siguen como omisiones explícitas; los hallazgos parciales llevan cobertura. Los hashes exactos del área de contenido y los hallazgos SimHash/LSH acotados se persisten en la auditoría nativa sin requerir un directorio HTML de SF. Las bandas LSH adaptativas al umbral preservan la sensibilidad de los pares que cumplen el criterio, reduciendo los cubos de candidatos amplios; el agotamiento del presupuesto de análisis aproximado no descarta los hallazgos de hash exacto. - Las auditorías de SF ejecutan opcionalmente la similitud semántica y la revisión de título/H1 frente al cuerpo conservado, mediante un adaptador local aportado explícitamente o incrustaciones declaradas. No se selecciona automáticamente ningún modelo ni proveedor. La identidad del adaptador, los hashes de origen, las puntuaciones, los límites y las omisiones acompañan a los candidatos de revisión; la similitud semántica no afirma contenido duplicado, relevancia de consulta ni canibalización. Las dos filas semánticas de cobertura de SF siguen como huecos hasta que se seleccione y valide un adaptador real. La autorización de proveedores externos requiere el booleano literal true; las cadenas o enteros truthy nunca autorizan una llamada de incrustación.

    #1307 (incidencia en GitHub)
  • CambiadoFuncionaLas referencias del buzón aceptan ids de objetivo (inbox:<uuid>), para que una nota#1314

    pueda citar el objetivo al que se refiere. - Los elementos del checklist que nunca se intentaron y son manuales muestran el estado not_run en lugar de review; solo un intento pendiente de decisión permanece en review. - El modelo de lectura de Issues (evidencia de hallazgos de observe) informa de recuentos por comprobación (by_check) y de un next_offset tras los primeros 20 hallazgos; findings_page pagina el resto.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaEscaneos de proyecto programados (#1322, núcleo): schedule.json en cada directorio de#1322

    proyecto guarda la programación independiente de ese sitio (días laborables y/o días del mes, una ventana horaria en la zona horaria del sitio, activar o desactivar, modo de rastreo spider/sitemap/list, presupuestos de URL y de solicitudes por ejecución, retardo de cortesía, user agent y estado de reanudación por segmento relativo al proyecto). El proyecto propietario puede incluir competidores vinculados, cada uno con su propia cadencia y política de escaneo. Los ajustes se editan con schedule-set / seo_schedule_set y expected_revision; schedule-show informa del estado de vencimiento y de la próxima ejecución del principal y de los competidores vinculados. schedule-run-due es un punto de entrada sin interfaz que ejecuta solo los escaneos que vencen de forma independiente, mantiene bloqueos con alcance de proceso hasta que termina cada ejecución, registra el estado de cancelación antes de relanzarla, y anota en cada proyecto afectado los resultados o el solapamiento de competidores. schedule-install y schedule-uninstall escriben o eliminan un plist de launchd, una línea de cron o un comando de Task Scheduler solo cuando se invocan explícitamente. - Agentes de usuario de rastreo: preajustes (spiderhead, googlebot, googlebot-desktop, googlebot-smartphone, bingbot, yandexbot, yandexmobilebot, baiduspider, duckduckbot, applebot, gptbot, claudebot, perplexitybot, y navegadores de escritorio y móviles) o una cadena personalizada. El valor predeterminado es ahora SpiderHeadBot/<version> (+https://github.com/PavloSEO/spiderhead), y la coincidencia del grupo de robots.txt usa la misma identidad. Los sitios que coincidían con el antiguo grupo de robots de SEOHEAD-Tools deben nombrar SpiderHeadBot en sus reglas.

    #1322 (incidencia en GitHub)
  • CambiadoFuncionaworkflow-start solo necesita un objetivo de propietario aceptado: basta con --goal-id#1314

    (o context.goal_id). El prompt registrado usa por defecto skill:workflow/full-audit-v1 y la tarea del checklist usa por defecto la que crea el objetivo aceptado (custom:goal-<entry>). Los rechazos nombran el comando del propietario que corrige el vínculo que falta. Las opciones se documentan en seohead workflow-start --help. - Las poblaciones del checklist aceptan objetos parciales: solo kind y source son obligatorios, y las demás claves toman el valor no definido por defecto. Una población rechazada indica sus claves faltantes o desconocidas. - Los rastreos de proyecto nativos recurren al /sitemap.xml del origen cuando robots.txt no declara ningún sitemap. Una alternativa ausente se registra como incompleta, pero no interrumpe el rastreo.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaLos espacios de trabajo de competidores conservan la URL tal como se introdujo: el#1314

    rastreo de un competidor parte de su URL www en lugar del host desnudo, y un rastreo de una URL de competidor ya no marca los elementos del checklist del propietario; el resultado se registra solo en el espacio de trabajo del propio competidor. Al abrir un proyecto con un espacio de trabajo de competidor dañado se informa de que ese competidor no está disponible, en lugar de fallar.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaLa cobertura del checklist de proyecto vincula ahora los informes audit.v2 en streaming:

    report-build --project y audit-workflow --action report adjuntan la instantánea del checklist a la salida de resumen en xlsx, docx, csv, md y PDF, en lugar de construir un informe sin vincular. Un escaneo detenido por su presupuesto de URL (stopped_by_budget) se acepta como último escaneo auditado del proyecto, y su informe indica el alcance limitado. report-build --input acepta la clave format. report-build --project --format json sobre una auditoría en streaming se rechaza con una explicación, porque el JSON se escribe literalmente y no puede incluir la instantánea del checklist.

Planificado

Hoja de ruta

108 abiertas

Hitos abiertos en GitHub. Cada línea es una incidencia abierta: trabajo planificado, aún no publicado.

Lo básico del escritorio

10 de 14 cerradas

Primero que la app de escritorio funcione: bloqueos, tamaño 800×600, pestañas muertas, estados honestos (ola 1 del plan)

  • AñadidoPlanificadoDesktop: recorrido del propietario en un proyecto real (visual, escaneos, incidencias,#1358

    exportaciones, herramientas)

    #1358 (incidencia en GitHub)
  • CorregidoPlanificadoDesktop: pestañas inactivas, acciones deshabilitadas y pantallas provisionales#1347 (incidencia en GitHub)
  • AñadidoPlanificadoWindows: fallan el rastreo nativo, el diario del proyecto y la compilación de Desktop;#1345

    Desktop abre ventanas en blanco en masa y es inutilizable en 4K

    #1345 (incidencia en GitHub)

Paridad del escritorio

19 de 34 cerradas

Patrones de UX a la par: pestañas, columnas por filtro, detalle desde el resumen, diseño persistente (épica #1522)

Motor de rastreo

9 de 51 cerradas

Cortesía y políticas de robots, reintentos, presupuestos, descubrimiento, escala de almacenamiento, ciclo del escaneo (épica #1520)

Análisis y campos de datos

10 de 64 cerradas

Legibilidad, vectores y rasgos semánticos, campos por URL, cobertura de comprobaciones, resúmenes (épica #1521)

Proyectos y flujos

8 de 10 cerradas

Flujos del propietario: tareas, exportaciones, informes programados y su entrega (épica #1314)

Cambio de marca

0 de 1 cerradas

Renombrado seohead → spiderhead: CLI, paquete, entorno, documentación (#1523)

  • AñadidoPlanificadoRenombrar el binario de la CLI, el paquete y el prefijo de variables de entorno de#1523

    seohead a spiderhead

    #1523 (incidencia en GitHub)

Interfaces CLI y MCP

7 de 12 cerradas

Mensajes de error claros, ayuda real, salidas de lectura acotadas, transportes MCP (épicas #1410 #1421)

  • AñadidoPlanificadoServidor MCP como modo de primera clase de la CLI con transportes stdio y streamable HTTP#1525 (incidencia en GitHub)
  • CorregidoPlanificadoMostrar la subayuda real de 'seohead sf' en lugar de un marcador de argumentos reenviados#1406 (incidencia en GitHub)

Capa de IA

0 de 1 cerradas

Destinos de prompt por elemento SEO sobre seo_ai_column, sin depender del proveedor (#1524)

  • AñadidoPlanificadoAnálisis de páginas asistido por IA con objetivos de prompt configurables sobre los datos#1524

    del rastreo

    #1524 (incidencia en GitHub)

Calidad de ingeniería

0 de 2 cerradas

División en módulos de los archivos gigantes y dirección de dependencias (#1514 #1515)

  • AñadidoPlanificadoDirección de dependencias: eliminar las inversiones de importación del core hacia las#1515

    funciones

    #1515 (incidencia en GitHub)
  • AñadidoPlanificadoDividir los módulos de adaptadores y motores demasiado grandes en unidades cohesivas#1514 (incidencia en GitHub)

Distribution: installers & one-command install

0 de 2 cerradas

Sales-readiness theme: native installers per OS, our own package name, and a one-command CLI install. Being ready to ship is the point of this milestone.

Versión

3.1.0

Primera versión etiquetada tras el cambio de nombre desde SEOHEAD Tools11 de octubre de 2026
455 entradas · Primera versión etiquetada tras el cambio de nombre desde SEOHEAD Tools138 añadido275 cambiado42 corregido

11 de octubre de 2026

5 añadido54 cambiado2 corregido
  • CambiadoFuncionaRehace Project settings (Schedule y Crawl) con componentes nativos de lienzo compartidos,#1323

    fuentes Roboto sin conexión…

    Rehace Project settings (Schedule y Crawl) con componentes nativos de lienzo compartidos, fuentes Roboto y Material Symbols sin conexión, y un diseño de una sola columna a 800 px.

    #1323 (incidencia en GitHub)
  • CambiadoFuncionaUsa inglés en toda la interfaz de la aplicación, conserva el comando de programación#1323

    existente y los contratos de documentos, y muestra solo datos de programación respaldados por el núcleo.

    #1323 (incidencia en GitHub)
  • CambiadoFuncionaConserva las identidades y alias de los espacios de trabajo mientras Project settings#1323

    está abierto; impide guardados duplicados…

    Conserva las identidades y alias de los espacios de trabajo mientras Project settings está abierto, e impide guardados duplicados mientras el núcleo responde.

    #1323 (incidencia en GitHub)
  • CambiadoFuncionaEscritorio: los ajustes del proyecto ganan una pestaña Schedule (días laborables, días#1322

    del mes, ventana de ejecución, zona horaria…

    Los ajustes del proyecto de escritorio ganan una pestaña Schedule (días laborables, días del mes, ventana de ejecución, zona horaria, competidores) y una pestaña Crawl (modo de rastreo, preajuste o cadena personalizada de User-Agent, pausa entre solicitudes, presupuesto de URL, SpiderHeadBot o un user agent personalizado); ambas leen y escriben el proyecto a través del núcleo, y la vista general del proyecto muestra la próxima y la última ejecución programada. Un modo --tray ejecuta los escaneos vencidos del núcleo y mantiene el Mac despierto solo mientras se ejecuta un escaneo.

    #1322 (incidencia en GitHub)
  • CambiadoFuncionaAnálisis programados del proyecto (#1322, núcleo): schedule.json en el directorio del#1322

    proyecto guarda la programación: días laborables y/o días del mes, una ventana horaria en la zona horaria del sitio, activar o desactivar, competidores, modo de rastreo spider/sitemap/list, presupuestos de URL y de peticiones por ejecución, pausa de cortesía y modo por tramos, que reanuda el rastreo parcial anterior. Se edita con schedule-set / seo_schedule_set y expected_revision, y schedule-show muestra la última ejecución y la siguiente ventana prevista. schedule-run-due es un punto de entrada sin interfaz que ejecuta solo los análisis vencidos, rechaza el solapamiento mediante un bloqueo (lease) y registra cada decisión en el diario del proyecto. schedule-install y schedule-uninstall escriben o eliminan un plist de launchd, una línea de cron o un comando del Programador de tareas solo cuando se invocan de forma explícita.

    #1322 (incidencia en GitHub)
  • CambiadoFuncionaUser agents de rastreo (#1322): perfiles (spiderhead, googlebot, googlebot-desktop…#1322

    User agents de rastreo (#1322): perfiles predefinidos (spiderhead, googlebot, googlebot-desktop, googlebot-smartphone, bingbot, yandexbot, yandexmobilebot, baiduspider, duckduckbot, applebot, gptbot, claudebot, perplexitybot, además de navegadores de escritorio y móviles) o una cadena personalizada. El valor por defecto es ahora SpiderHeadBot/<version> (+https://github.com/PavloSEO/spiderhead), y la coincidencia de grupos en robots.txt usa la misma identidad. Los sitios que coincidían con el grupo robots de SEOHEAD-Tools deben nombrar SpiderHeadBot en sus reglas.

    #1322 (incidencia en GitHub)
  • CambiadoFuncionaUn análisis guardado del proyecto ahora marca los elementos automáticos de la lista de#1314

    comprobación que midió.

    Cada elemento de comprobación activado se resuelve en uno de tres resultados: succeeded, cuando la auditoría guardada ejecutó la comprobación y el análisis sirve de evidencia; unavailable, cuando el rastreo la omitió o la desactivó, conservando su motivo; o unmeasured, cuando la auditoría no menciona la comprobación. Un elemento no medido conserva su registro anterior y se informa por nombre en checklist_evidence, así que nunca cuenta como 0. Un rastreo que falla o se interrumpe marca sus comprobaciones automáticas como failed con el motivo del fallo. El mismo camino de registro sirve ahora también al flujo prepare, que antes tenía su propia copia del bucle. Un proyecto cuya lista de comprobación no está inicializada se omite, con el motivo indicado.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaLos espacios de competidores conservan la URL tal como se introdujo: el rastreo de un#1314

    competidor parte de su URL www en lugar del dominio desnudo, y un rastreo de la URL de un competidor ya no marca los elementos de la lista de comprobación del propietario; el resultado se registra solo en el espacio del propio competidor. Al abrir un proyecto con un espacio de competidor dañado, ese competidor se informa como no disponible en lugar de hacer fallar la operación.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaLos candidatos a competidor se pueden registrar, listar y eliminar desde la CLI#1314

    (project-competitors-add, project-competitors-list, project-competitors-remove) y con las herramientas MCP seo_project_competitors_* correspondientes. Cada candidato conserva la URL tal como se introdujo, incluido un host www, y los hosts con y sin www cuentan como el mismo sitio en las comprobaciones de duplicados. Un competidor con host www ya no rompe la preparación ni hace que project-observe falle.

    #1314 (incidencia en GitHub)
  • CambiadoFunciona--max-urls es ahora el presupuesto de páginas del rastreo: un presupuesto explícito#1314

    completa los presupuestos de peticiones y de tiempo que no estén definidos…

    --max-urls es ahora el presupuesto de páginas del rastreo: un presupuesto explícito de páginas completa los presupuestos de peticiones y de tiempo que no estén definidos (3 peticiones y 2 segundos por página), de modo que los rastreos de 50 a 300 páginas se admiten sin approve_large_crawl. Los presupuestos por encima de los umbrales del proyecto siguen rechazándose.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaUna parada deliberada por presupuesto de URL se guarda como captura terminada con#1314

    finish_reason…

    Una parada deliberada por presupuesto de URL se guarda como captura terminada, con finish_reason stopped_by_budget y una hora finished_at, en lugar de interrupted sin hora de fin. Sus URL en cola siguen disponibles para reanudar el rastreo.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaLas URL de competidores conservan el host tal como se introdujo (por ejemplo, www. se#1314

    mantiene), en lugar de guardarse sin él.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaLa aplicación de escritorio añade sitios de competidores desde el portapapeles o uno a#1314

    uno a través del núcleo, fija un límite de URL por sitio e inicia sus análisis en paralelo. Un competidor aparece como analizado solo después de un análisis conservado y terminado.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaLos análisis nativos miden HSTS, contenido mixto y datos estructurados a partir de su#1314

    propia evidencia guardada, así que una exportación de SF ausente o desactualizada ya no los marca como ausentes. duplicate-check marca como no medida una ejecución con cero pares comparados. Las incidencias de plantilla en todo el sitio (mismo encabezado de la plantilla común, ratio bajo de texto) son ahora una sola incidencia con el número de páginas (#1314).

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaAceptar un objetivo del propietario añade solo la tarea de comprobación de ese objetivo.#1314

    Ya no reconcilia todo el catálogo integrado en coverage.json; las filas integradas se añaden bajo demanda cuando se toca alguna.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaUna lista de comprobación ocupada nombra al titular activo (por ejemplo, un rastreo#1314

    nativo en marcha y su pid) en lugar de llamar residuo al bloqueo. El bloqueo registra el pid de quien escribe; un bloqueo sin titular activo sigue informándose como residuo.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaUna ejecución de flujo bloqueada por un paso fallido, no disponible, omitido o#1314

    interrumpido sigue siendo reanudable, y un paso pendiente posterior puede guardarse como punto de control aunque sobrepase un paso que no tuvo éxito. Los pasos siguen debiendo registrarse como punto de control en el orden registrado, y una ejecución interrumpida sigue rechazando nuevos pasos.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaUna revisión registrada por un agente ya no marca como completado para el propietario un#1314

    elemento manual o entregable.

    El elemento sigue pendiente de la aprobación del propietario o de un revisor que no sea agente.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaLas referencias de la bandeja de entrada aceptan ids de objetivo (inbox:<uuid>), para#1314

    que una nota pueda citar el objetivo al que se refiere.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaLos elementos de la lista de comprobación que nunca se intentaron y son manuales muestran#1314

    el estado not_run en lugar de review; solo un intento pendiente de decisión permanece en review.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaEl modelo de lectura de Issues (evidencia de las incidencias de observe) informa de#1314

    recuentos por comprobación (by_check) y de un next_offset tras las primeras 20 incidencias; findings_page pagina el resto.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaComprobaciones nativas del rastreo (#1314): el tamaño de imagen (IMG_OVER_KB) se mide#1314

    ahora a partir de las descargas de imágenes propias del rastreo, y el estado del sitemap (SITEMAP_URL_4XX_5XX, SITEMAP_URL_3XX, SITEMAP_URL_NON_INDEXABLE) a partir de la descarga propia de cada URL listada en el sitemap. Una URL listada que el rastreo nunca solicitó se cuenta como no medida, nunca como correcta. IMG_MISSING_ALT, IMG_MISSING_DIMENSIONS y HREFLANG_ERROR indican en un análisis nativo que el rastreo no los mide tal como los define la exportación de SF, en lugar de apuntar a un filtro de SF. La falta de evidencia de hreflang y de contenido mixto en un análisis nativo se informa como no medida por el rastreo nativo, no como una exportación ausente.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaDiario del proyecto (#1314): cada evento del proyecto se escribe ahora también como una#1314

    viñeta en log.md…

    Diario del proyecto (#1314): cada evento del proyecto se escribe ahora también como una viñeta en log.md, y el núcleo registra entradas automáticas para los rastreos terminados (scans), los informes de proyecto generados y los intentos de la lista de comprobación (agent). Las entradas van a events.jsonl y las lee project-event-page. Los hooks automáticos nunca hacen fallar el rastreo, el informe o el paso de la lista que describen. project-event-append y seo_project_event_append mantienen su interfaz y añaden la línea en log.md.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaEl rastreo nativo ahora guarda las cabeceras de seguridad que leen las comprobaciones#1314

    (Strict-Transport-Security, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy). Antes se descartaban al capturar, así que un sitio que enviaba HSTS se informaba como si no lo tuviera. Las cabeceras Set-Cookie solo guardan sus flags (secure, httponly, samesite=), nunca el nombre ni el valor de la cookie. Una cabecera de seguridad enviada más de una vez en la misma página se informa como DUPLICATE_SECURITY_HEADER.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaworkflow-start necesita solo un objetivo del propietario aceptado: --goal-id (o#1314

    context.goal_id)…

    workflow-start necesita solo un objetivo del propietario aceptado: basta con --goal-id (o context.goal_id). El prompt registrado usa por defecto skill:workflow/full-audit-v1, y la tarea de la lista de comprobación usa por defecto la que creó la aceptación del objetivo (custom:goal-<entry>). Los rechazos indican el comando del propietario que corrige el vínculo que falta. Las opciones están documentadas en seohead workflow-start --help.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaLas poblaciones de la lista de comprobación aceptan objetos parciales: solo kind y#1314

    source son obligatorios, y el resto de claves quedan sin definir por defecto. Una población rechazada indica sus claves ausentes o desconocidas.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaLos rastreos nativos del proyecto recurren al /sitemap.xml del origen cuando robots.txt#1314

    declara…

    Los rastreos nativos del proyecto recurren al /sitemap.xml del origen cuando robots.txt no declara ningún sitemap. Si esa alternativa no existe, se registra como incompleta, pero no interrumpe el rastreo.

    #1314 (incidencia en GitHub)
  • CambiadoFuncionaLos logs del servidor conservan ahora los totales exactos de IP de bots en disco en lugar#1311

    de una muestra limitada, con registros por IP acotados, visitas, última visita y filtros por subred. La verificación DNS explícita comprueba cada IP seleccionada por separado, registra la evidencia PTR y de resolución directa, admite IPv6 y conserva los resultados no disponibles o de tiempo agotado como no comprobados. Las cachés locales caducan a la hora; las lecturas nunca disparan consultas DNS.

    #1311 (incidencia en GitHub)
  • AñadidoFuncionaAñadidos importar logs locales del proyecto, resumen paginado, evidencia de bots y cruce#1311

    con análisis nativos…

    Añadidos importar logs locales del proyecto, resumen paginado, evidencia de bots y comandos de cruce con el análisis nativo, a través de los mismos manejadores de CLI y MCP. Los artefactos de log separados conservan particiones por fecha y la cobertura y procedencia de cada fuente, sin cambiar los esquemas congelados de los análisis. Si falta evidencia o está incompleta, no se emiten conclusiones de ausencia. Las pantallas de logs del escritorio quedan como una tarea de presentación aparte.

    #1311 (incidencia en GitHub)
  • CambiadoFuncionaControlar las llamadas de producción a DataForSEO de Google antes de construir el#1310

    cliente, mostrar cotizaciones offline…

    Las llamadas de producción a DataForSEO de Google se controlan antes de construir el cliente, muestran cotizaciones offline a partir de los precios del proveedor proporcionados, tienen en cuenta la profundidad de SERP y los cargos por operadores de búsqueda, y aplican los techos conocidos en USD por llamada antes del transporte. Amplía las operaciones acotadas de índice de backlinks y registra los costes ausentes o las formas de respuesta mal formadas como recibos inciertos. Los límites de moneda por proyecto y por mes siguen pendientes de una decisión del propietario.

    #1310 (incidencia en GitHub)
  • CambiadoFuncionaFusionar la evidencia explícita de origen e importación de backlinks en instantáneas de#1310

    historial locales privadas con…

    Fusiona la evidencia explícita de origen e importación de backlinks en instantáneas de historial locales privadas, con observaciones completas de tokens rel, anclas, dominios de referencia, filtros y señales transparentes de revisión de spam. Añade rutas CLI/MCP de perfil y de exportación revisada de disavow, sin envíos automáticos.

    #1310 (incidencia en GitHub)
  • AñadidoFuncionaAñade avisos de revisión por tokens rel mixtos y por divulgación de patrocinio saliente,#1310

    a partir de la evidencia nativa conservada. Conserva el contexto no disponible, los recuentos nulos para poblaciones de HTML sin analizar por completo y las clases sponsored, ugc y nofollow en los informes y en las comprobaciones de donantes, sin cambiar el esquema congelado de análisis conservados.

    #1310 (incidencia en GitHub)
  • CambiadoFuncionaLas comprobaciones nativas de DOM y de duplicados leen ahora el documento conservado#1307

    seleccionado de cada página por URL exacta, con linaje verificado de respuesta y cuerpo. La retención desactivada, los cuerpos ausentes, no válidos o que superan el presupuesto siguen siendo omisiones explícitas, y las incidencias parciales llevan cobertura. Los hashes exactos del área de contenido y las incidencias SimHash/LSH acotadas se guardan en la auditoría nativa sin necesidad de un directorio HTML de SF. Las bandas LSH adaptadas al umbral preservan la recuperación de los pares que cumplen el criterio mientras reducen los cubos de candidatos amplios; el agotamiento del presupuesto de análisis de similitud no descarta los hashes exactos.

    #1307 (incidencia en GitHub)
  • CambiadoFuncionaLas auditorías SF ejecutan opcionalmente similitud semántica y revisión de title/H1#1307

    frente al cuerpo conservado, con un adaptador local indicado de forma explícita o con embeddings declarados. No se selecciona automáticamente ningún modelo ni proveedor. La identidad del adaptador, los hashes de origen, las puntuaciones, los límites y las omisiones acompañan a los candidatos de revisión. La similitud semántica no afirma contenido duplicado, relevancia de consulta ni canibalización. Las dos filas de cobertura semántica de SF siguen como huecos hasta que se seleccione y valide un adaptador real. La autorización de un proveedor externo exige el booleano literal true; las cadenas o los enteros que solo parecen verdaderos nunca autorizan una llamada de embeddings.

    #1307 (incidencia en GitHub)
  • CambiadoFuncionaLas auditorías nativas conservadas agrupan ahora los enlaces internos rotos por destino#1306

    observado, con evidencia de origen y de texto ancla; registran cadenas y bucles de redirección con el estado de cada salto; distinguen la búsqueda interna por ruta y los anclas vacías, y muestran los resultados capturados de externos sin respuesta. Las incidencias de consistencia de sitemap y robots usan la pertenencia y la evidencia de respuesta conservadas, sin nuevas descargas en vivo; la evidencia ausente o parcial sigue siendo explícita.

    #1306 (incidencia en GitHub)
  • AñadidoFuncionaAñade un grafo acotado de enlaces de análisis guardados con filtros de posición, sección#1306

    y vecindario local…

    Añade un grafo acotado de enlaces de análisis guardados, con filtros de posición, sección y vecindario local, agregación por sección y cambios de aristas entre análisis. El reanálisis offline completa las posiciones con lotes derivados reanudables e informa de la evidencia sin clasificar en la inspección de enlaces y en el estado del análisis, preservando el esquema congelado scan.v1.

    #1306 (incidencia en GitHub)
  • AñadidoFuncionaAñade generación local de sitemap XML a partir de páginas 200 canónicas e indexables#1306

    conservadas, con lastmod observado, exclusiones, división por protocolo, índice de sitemap y sitemap de imágenes opcional. La CLI y el MCP comparten las mismas implementaciones; la publicación de la salida exige un directorio local nuevo y nunca despliega archivos.

    #1306 (incidencia en GitHub)
  • CambiadoFuncionaConserva los objetivos de descubrimiento ausentes en el momento de la captura cuando un#1306

    procesamiento posterior de sitemap o de semillas (seed) añade la URL…

    Conserva los objetivos de descubrimiento ausentes en el momento de la captura cuando un procesamiento posterior de sitemap o de semillas añade la URL al catálogo conservado. La evidencia explicada de no resueltos o excluidos sigue siendo inmutable, mientras que los objetivos conocidos reclamados y las discrepancias de identidad no nulas siguen siendo inválidos.

    #1306 (incidencia en GitHub)
  • CambiadoFuncionaLa generación de sitemap de imágenes excluye las respuestas de recurso no 200 conocidas,#1306

    aunque el recurso no se haya guardado como página rastreada, y marca las respuestas de imagen no medidas como cobertura parcial.

    #1306 (incidencia en GitHub)
  • CambiadoFuncionaConserva los atributos canonical y de paginación brutos como contexto versionado del#1305

    documento, sin cambiar el SQL congelado del análisis. Las etiquetas canonical con atributos hreflang, lang, media o type no soportados, las anotaciones malformadas y las declaraciones entre hosts o protocolos generan ahora incidencias ligadas a la evidencia; las palabras clave de relación bien formadas pero desconocidas siguen sin clasificar.

    #1305 (incidencia en GitHub)
  • CambiadoFuncionaAmplía las sondas acotadas a objetivos del mismo host a la paginación y conserva las#1305

    observaciones medidas de noindex y canonical. Las cadenas canonical nativas y las incidencias de noindex en canonical o hreflang pueden usar sondas; las sondas heredadas de solo estado siguen siendo legibles y no medidas para las directivas HTML.

    #1305 (incidencia en GitHub)
  • CambiadoFuncionaEvalúa las cadenas de paginación nativas opacas en busca de contradicciones recíprocas#1305

    explícitas de next/prev, conservando las reglas numeradas o de paso y los estados sin juzgar con nombre. Selecciona las URL de incidencias guardadas, incluidos los miembros agrupados, mediante scan-url-query, con tablas SQLite temporales y evidencia audit.v2 en streaming.

    #1305 (incidencia en GitHub)
  • CorregidoFuncionaMantiene sin clasificar los tokens de relación Unicode desconocidos y con signos de#1305

    puntuación, normaliza las autoridades canonical equivalentes (IDN y puerto por defecto) y conserva las rutas exactas de destino de paginación nativa. Los tokens de página mixtos ilegibles siguen sin juzgar; el defecto de paginación de la tienda se detecta incluso cuando la página uno no tiene número en su URL.

    #1305 (incidencia en GitHub)
  • CambiadoFuncionaRenderiza las anotaciones next/prev declaradas del fixture de la tienda para que su#1305

    referencia de paginación D41 se sirva realmente y el rastreo nativo pueda validarla.

    #1305 (incidencia en GitHub)
  • CambiadoFuncionaConserva la evidencia estática de AMP y de accesibilidad ligada al documento en las filas#1304

    de contexto de análisis existentes, respetando el esquema SQL congelado scan.v1. Las incidencias estructurales de AMP revisan el doctype original, head y body, el charset UTF-8, el viewport, el script de runtime y las declaraciones de boilerplate; los destinos AMP emparejados sin marcador de raíz AMP se identifican por separado. Las reglas completas del validador de AMP siguen sin estar disponibles a la espera de una decisión sobre la licencia.

    #1304 (incidencia en GitHub)
  • CambiadoFuncionaPrimeras incidencias de accesibilidad: idioma del documento, etiquetas de formulario,#1304

    alternativas de imagen, saltos de encabezado y el landmark principal. Las incidencias conservan ejemplos acotados y recuentos completos de ocurrencias. El contraste calculado y las reglas de axe-core renderizadas siguen sin medirse.

    #1304 (incidencia en GitHub)
  • CambiadoFuncionaValida Schema.org Microdata y los sujetos y propiedades RDFa comunes con el vocabulario#1304

    incluido y las reglas de resultados enriquecidos existentes. Los errores, advertencias y propiedades obligatorias ausentes conservados por URL se convierten en incidencias nativas. Las construcciones RDFa no soportadas son evidencia parcial explícita, no un resultado de validación limpio.

    #1304 (incidencia en GitHub)
  • CambiadoFuncionaSirve los árboles JSON-LD analizados junto con los errores de origen, posición y sintaxis#1304

    de cada bloque en scan-structured-blocks…

    Sirve los árboles JSON-LD analizados junto con los errores de origen, posición y sintaxis de cada bloque en scan-structured-blocks; limita los árboles de propiedades anchos y expone ese límite. Lee el último documento de una URL y representación solicitadas sin cambiar su análisis.

    #1304 (incidencia en GitHub)
  • CambiadoFuncionaConserva la evidencia estructurada parcial o no disponible sin ocultar los errores#1304

    hermanos confirmados.

    Resuelve las identidades JSON-LD soportadas frente a la misma base de documento que el marcado HTML, conservando el JSON original. Rechaza los bloques JSON escalares o vacíos como grafos válidos, y comparte la selección normalizada de etiquetas JSON-LD en vivo entre el analizador y las proyecciones servidas.

    #1304 (incidencia en GitHub)
  • CambiadoFuncionaLas auditorías nativas muestran ahora el marcado de cabecera que bloquea el renderizado a#1303

    partir del HTML conservado completo, sin cambiar el esquema congelado scan.v1. Los cuerpos ausentes, incompletos o limitados por presupuesto siguen sin estar disponibles. Se reutilizan la detección existente de recursos de cabecera y la entrada de extracción personalizada de SF.

    #1303 (incidencia en GitHub)
  • AñadidoFuncionaAñade presupuestos configurables de bytes para la navegación observada nativa y para cada#1303

    recurso individual, señales de entrega de caché y de fuentes, heurísticas de minificación y de scripts heredados, y duplicados exactos de scripts en la misma página, a partir de la evidencia scan.v2 conservada. Los datos no descargados y las cargas de runtime incompletas siguen siendo explícitos; las declaraciones responsive no se suman como peso de runtime. Los límites inferiores solo para HTML, los recuentos escalares de cobertura, las muestras de fuentes y los resúmenes de origen siguen siendo explícitos y acotados.

    #1303 (incidencia en GitHub)
  • CambiadoFuncionaRecoge la cobertura precisa de JS/CSS de Chromium, acotada, en los renders solicitados,#1303

    conserva resúmenes de uso UTF-16…

    Recoge la cobertura precisa de JS/CSS de Chromium, acotada, en los renders solicitados; conserva resúmenes de uso UTF-16 y hallazgos de dimensionado de imágenes renderizadas, y los lee al reabrir o en el reanálisis offline. Los motores no soportados y las mediciones ausentes no se convierten en resultados limpios.

    #1303 (incidencia en GitHub)
  • CambiadoFuncionaAcepta JSON de Lighthouse por URL, acotado y coincidente, para el descubrimiento de LCP,#1303

    árboles de dependencias, responsables de desplazamiento de diseño, entrega de imágenes, reflow forzado y ejecución de scripts, con procedencia de la captura y hashes de entrada. No se añade ningún proceso de Lighthouse, proveedor de pago ni inferencia de CWV de campo. Se actualizan el registro, la cobertura de SF y la documentación de referencia generada.

    #1303 (incidencia en GitHub)
  • CorregidoFuncionaLos umbrales aditivos de activos quedan fuera de la cabecera congelada del análisis#1303

    nativo y sus valores exactos se guardan…

    Los umbrales aditivos de activos quedan fuera de la cabecera congelada del análisis nativo, y sus valores exactos se guardan en un contexto de ejecución validado y versionado. La reanudación compara estos valores por separado, y el reanálisis offline los restaura desde la evidencia conservada. Los lectores ligeros anteriores pueden seguir inspeccionando la forma, sin cambios, de la configuración de cabecera.

    #1303 (incidencia en GitHub)
  • CambiadoFuncionarecord de la lista de comprobación acepta ahora una comprobación automática con éxito

    cuyo análisis guardado es un audit.v2 en streaming; antes fallaba con 'NoneType' object is not subscriptable, porque la auditoría vive en el archivo auxiliar (companion) y no en la tabla heredada del análisis. Los formatos de registro aceptados están documentados en seohead project checklist-record --help, en el esquema MCP seo_project_checklist_record y en docs/INPUTS.md.

  • CambiadoFuncionaEjecuta la suite completa del toolkit una vez en Python 3.15, en lugar de una matriz de

    versiones anteriores, conservando cuatro grupos de pruebas verificados y la cobertura combinada. Usa la misma versión estable de Python para los arranques de CI y de compilación de releases.

  • CambiadoFuncionaLa lista Work del escritorio lee cada página de la lista de comprobación (100 por

    petición) en lugar de las primeras 50 filas. Issues muestra cada comprobación del núcleo según el registro, en lugar de mostrar «Other check».

  • CambiadoFuncionaDesktop Work lee cada página de la lista de comprobación, pero muestra el panel de tareas

    del proyecto de una página cada vez, así que una lista de cualquier tamaño ya no falla con «at most 100 rows». Si el propietario no ha elegido ninguno, el escritorio abre el análisis que deja una auditoría completa (el análisis completo más grande), y el descubrimiento del núcleo comprueba también el propio entorno del intérprete del escritorio (sys.prefix) antes que PATH.

  • CambiadoFuncionaConsolida las comprobaciones de auditoría conservadas y las mejoras nativas del

    escritorio.

    Conserva los ajustes de presupuesto de recursos sin cambiar la cabecera congelada del análisis, mantiene el reanálisis offline seguro y la reanudación, y comparte los componentes nativos de ajustes del proyecto, los tokens de tema y las fuentes incluidas. Elimina los insumos de diseño privados del árbol distribuido.

  • CambiadoFuncionaVincula las revalidaciones de remediación a la política de activos efectiva validada,

    conservando la cabecera original del análisis y los bytes de origen.

  • CambiadoFuncionaLa cobertura de la lista de comprobación del proyecto ahora vincula los informes audit.v2

    en streaming: report-build --project y audit-workflow --action report adjuntan la instantánea de la lista a la salida xlsx, docx, csv, md y PDF, en lugar de generar un informe sin vincular. Un análisis detenido por su presupuesto de URL (stopped_by_budget) se acepta como la última auditoría del proyecto, y su informe declara el alcance limitado. report-build --input acepta la clave format. report-build --project --format json sobre una auditoría en streaming se rechaza con una explicación, porque el JSON se escribe tal cual y no puede llevar la instantánea de la lista.

10 de octubre de 2026

16 añadido51 cambiado
  • CambiadoFuncionaEl monitor de análisis del escritorio sigue el tablero de diseño de ScanRun: porcentaje#1203

    real a partir de los contadores fetched/found, una barra de progreso de 10 px, el límite de frecuencia del recolector y un marcador de posición honesto de 120 px para el gráfico de velocidad (el historial de velocidad del núcleo se sigue en #1203).

    #1203 (incidencia en GitHub)
  • CambiadoFuncionacheck_sample en seohead/checks/custom_extract.py ejecuta extractores CSS, XPath y#1059

    regex…

    check_sample en seohead/checks/custom_extract.py ejecuta los extractores CSS, XPath y regex sobre un único documento HTML guardado, sin análisis ni petición de red. Cada resultado incluye sus valores y un reason para un resultado vacío (no_match, empty_html o budget_exceeded), de modo que una respuesta vacía nunca se presenta como un resultado limpio (#1059). Es solo una llamada del núcleo: todavía no hay ninguna herramienta CLI ni MCP registrada, y obtener una URL en vivo está deliberadamente excluido.

    #1059 (incidencia en GitHub)
  • CambiadoFuncionaLa comprobación de secuencia de paginación (PAGINATION_SEQUENCE_ERROR) evalúa ahora las#1057

    series con paso: cuando un paso cubre la mayoría de los pasos de una serie, se informa de la ruptura de ese paso (?page=1,3,5,8 se rompe al pasar de 5 a 8). Los esquemas de desplazamiento irregulares y las series sin números siguen sin evaluarse y se nombran como omitidos.

    #1057 (incidencia en GitHub)
  • AñadidoFuncionaNueva comprobación de rastreo INTERNAL_NOFOLLOW_OUTLINKS (aviso): indica cada página de#1052

    origen que contiene enlaces salientes internos con nofollow, con su número y una muestra acotada de destinos. Cubre el hueco a nivel de página de la fila «Internal Nofollow Outlinks» de Screaming Frog, que estaba como partial. Se ejecuta en los rastreos nativos y se omite por nombre en las ejecuciones solo de exportación y en las de lista de URL.

    #1052 (incidencia en GitHub)
  • CambiadoFuncionaEl parser lee <link rel="alternate"> con calificador de medios y sin hreflang (una#1051

    URL…

    El parser lee las declaraciones <link rel="alternate"> con calificador de medios y sin hreflang (una URL móvil independiente) en parse_html como mobile_alternates (#1051). La comprobación Mobile Alternate Link de SF sigue pendiente; la que compara el canonical de la URL móvil todavía no está escrita.

    #1051 (incidencia en GitHub)
  • AñadidoFuncionaAñade la comprobación HREFLANG_UNLINKED_TARGET (advertencia): un destino de alternativa#1050

    hreflang…

    Añade la comprobación HREFLANG_UNLINKED_TARGET (advertencia): se informa de cada destino de alternativa hreflang al que ningún enlace normal del rastreo apunta. Así queda cubierta la incidencia «Unlinked Hreflang URLs» de Screaming Frog. La comprobación lee la exportación All Hreflang y la columna Internal:All Inlinks, igual que UNLINKED_CANONICAL; una autorreferencia no cuenta, y un rastreo parcial no emite la incidencia. El registro pasa de 182 a 183 comprobaciones.

    #1050 (incidencia en GitHub)
  • CambiadoFuncionaDimensionado de imágenes en rutas renderizadas: render-check ahora registra el tamaño#1049

    intrínseco en píxeles de cada imagen frente a su caja renderizada y a la relación de píxeles del dispositivo (image_sizing: evidencia de sobredimensionado y de ampliación). Es solo evidencia; todavía no hay id de comprobación de SF-analyzer, así que «Incorrectly Sized Images» pasa de «gap» a «partial» (#1049).

    #1049 (incidencia en GitHub)
  • CambiadoFuncionaSemantically Similar: el estado sigue en gap y la nota ahora indica el bloqueo.#1041

    El comando y la herramienta MCP de similitud semántica existen, pero no se incluye ningún adaptador de embeddings y la ejecución de SF todavía no llama al módulo (#1041).

    #1041 (incidencia en GitHub)
  • AñadidoFuncionaAñade la comprobación INTERNAL_LINK_SPONSORED_UGC (aviso): un enlace del mismo sitio#1040

    que lleva…

    Añade la comprobación INTERNAL_LINK_SPONSORED_UGC (aviso): un enlace del mismo sitio con rel="sponsored" o rel="ugc" se informa con el conjunto completo de tokens de rel. Necesita link_attributes.capture, como las demás comprobaciones basadas en rel, y sin ese ajuste se informa como no medido.

    #1040 (incidencia en GitHub)
  • AñadidoFuncionaAñade la base de la generación de sitemaps XML a partir de un escaneo conservado:#1039

    select_indexable mantiene…

    Añade la base de la generación de sitemaps XML a partir de un escaneo conservado: select_indexable conserva solo las páginas HTML 200 autocanónicas, no noindex y no bloqueadas por robots, e indica el motivo de cada URL excluida; render_sitemaps escribe un <urlset>, o bien archivos divididos más un <sitemapindex> cada 50 000 URL o 52 428 800 bytes por archivo. La exposición en CLI y MCP llega después.

    #1039 (incidencia en GitHub)
  • AñadidoFuncionaAñade cloudflare-traffic (CLI) y seo_cloudflare_traffic (MCP): una fuente de solo#1026

    lectura de Cloudflare GraphQL Analytics para el analizador de logs cuando faltan los logs del origen (#1026, #1009). Devuelve bots × URL × códigos de estado × estado de caché por día, con la misma estructura que log-analyze, y se etiqueta como source: cloudflare-aggregated porque son datos agregados de borde, no logs sin procesar (no hay IP de cliente, así que no se puede verificar el DNS inverso). Los días que llenan el límite de 10 000 filas de la página se dividen por ventanas de tiempo; la llamada se registra en el libro de gasto como proveedor gratuito. El token procede de CLOUDFLARE_API_TOKEN o de SEOHEAD_CLOUDFLARE_TOKEN_FILE y nunca se muestra.

    #1026 (incidencia en GitHub)
  • CambiadoFuncionaEvaluador interno de incidencias de Search Console, todavía sin conectar a los informes:#1025

    seohead/checks/search_console_findings.py cruza las páginas del rastreo con un documento GSC normalizado y evalúa GSC_ORPHAN, NO_SEARCH_DATA y NON_INDEXABLE_WITH_SEARCH_DATA. Una comprobación se omite indicando su motivo cuando el rastreo es parcial, la ventana está incompleta, la recopilación es una muestra o está truncada, o no se aporta evidencia; una comprobación omitida nunca se informa como limpia.

    #1025 (incidencia en GitHub)
  • CambiadoFuncionacrawl-enrich informa de cuatro incidencias de analítica web a partir de un CSV sin#1024

    conexión con la URL como clave: URL huérfanas de analítica, páginas indexables sin datos de analítica, páginas no indexables con visitas y tasa de rebote superior al 70 %. Los parámetros --visits-column y --bounce-column eligen los datos; si falta una columna, se rechaza indicando su nombre; los valores ilegibles se cuentan y nunca se toman como cero, y las URL huérfanas de analítica no se informan en un rastreo parcial. La obtención en vivo por URL desde Metrika o GA4 todavía no está incluida (#990, #984).

    #1024 (incidencia en GitHub)
  • CambiadoFuncionaEl mapa de cobertura de incidencias de SF incluye las cuatro de analítica web (Orphan#1024

    URLs…

    El mapa de cobertura de incidencias de SF pasa a incluir las cuatro de analítica web («Orphan URLs», «Bounce Rate Above 70%», «No GA Data», «Non-Indexable with GA Data») como detectadas por crawl-enrich a partir de un CSV sin conexión, en lugar de fuera de alcance. sf run todavía no las emite.

    #1024 (incidencia en GitHub)
  • CambiadoFuncionaNúcleo de cobertura de laboratorio para CSS y JavaScript sin usar (#1023, primera#1023

    entrega): un analizador puro recibe las cargas de page.coverage de Playwright e informa de los caracteres sin usar por recurso, con una incidencia cuando un recurso está en gran parte sin usar y es grande. Recopilar la cobertura desde una página renderizada es la siguiente entrega.

    #1023 (incidencia en GitHub)
  • CambiadoFuncionaComprobaciones de pareja AMP (#1020): AMP_NON_200, AMP_MISSING_CANONICAL,#1020

    AMP_MISSING_RETURN_LINK, AMP_NON_INDEXABLE_CANONICAL y AMP_INDEXABLE leen el destino AMP que una página de escritorio declara con <link rel="amphtml">. Solo se juzgan las páginas AMP que capturó el rastreo; un destino no capturado se omite y queda registrado. El rastreo nativo ahora guarda el destino resuelto en la columna AMP HTML. Las otras diez reglas AMP de SF siguen descartadas.

    #1020 (incidencia en GitHub)
  • AñadidoFuncionaAñade HTML_OVER_2MB, un tope absoluto de 2 MB para el documento HTML, separado de#1019

    LARGE_HTML, que es relativo a la mediana. La incidencia «HTML Document Over 2MB» de Screaming Frog ahora se asigna a esta comprobación en lugar de a la regla de 200 KB.

    #1019 (incidencia en GitHub)
  • AñadidoFuncionaAñade el aviso URL_HAS_PARAMETERS a la auditoría de rastreo: una página HTML interna#1018

    cuya URL…

    Añade el aviso URL_HAS_PARAMETERS a la auditoría de rastreo: se informa de cualquier página HTML interna cuya URL lleva parámetros de consulta, independientemente de su estado de canonical. URL_HAS_PARAMS conserva su significado más estricto, solo para páginas sin canonical (#1018).

    #1018 (incidencia en GitHub)
  • CambiadoFuncionaDirectivas de robots (#1017): noodp y noydir obsoletas en meta robots o#1017

    X-Robots-Tag…

    Directivas de robots (#1017): las directivas obsoletas noodp y noydir en meta robots o en X-Robots-Tag ahora generan los avisos NOODP y NOYDIR en la auditoría de SF; antes figuraban como fuera de alcance. none (noindex + nofollow) queda cubierto por pruebas de regresión tanto para la ruta de X-Robots-Tag como para la de meta.

    #1017 (incidencia en GitHub)
  • AñadidoFuncionaNueva comprobación de rastreo JS_CONSOLE_ERRORS (SF «Pages with JavaScript Errors»):#1015

    una página cuya consola de renderizado conservada registró errores. Se lee sin conexión desde los archivos auxiliares de consola guardados de un escaneo nativo, sin volver a renderizar; un registro que no se puede leer se indica como omisión, nunca como página limpia. Requiere rendering.artifacts.console_errors.

    #1015 (incidencia en GitHub)
  • CambiadoFuncionaLos rastreos ahora informan de cuatro cabeceras HTTP de seguridad ausentes por página#1013

    HTML, a partir de la respuesta final guardada: MISSING_CSP, MISSING_X_CONTENT_TYPE_OPTIONS, MISSING_X_FRAME_OPTIONS (que se da por cumplida con la directiva frame-ancestors de CSP) y MISSING_REFERRER_POLICY. Las páginas cuyas cabeceras guardadas no se pueden analizar se cuentan como no medidas, no como limpias, y un rastreo sin escaneo guardado omite esas comprobaciones indicando el motivo.

    #1013 (incidencia en GitHub)
  • AñadidoFuncionaAñade un validador para especificaciones cerradas de acciones de página (click,#1011

    scroll, wait_for_selector…

    Añade un validador para las especificaciones cerradas de acciones de página (click, scroll, wait_for_selector, wait_ms) con un presupuesto de tiempo estático para los rastreos renderizados. Todavía no está conectado al renderizado, así que el comportamiento del rastreo no cambia (#1011).

    #1011 (incidencia en GitHub)
  • CambiadoFuncionalog-analyze lee logs de acceso comprimidos con gzip (archivos rotados access.log.N.gz#1009

    y…

    log-analyze lee directamente los logs de acceso comprimidos con gzip (archivos rotados access.log.N.gz y archivos comprimidos renombrados), detectando el formato por su contenido y no por la extensión. Un archivo truncado o dañado se informa como error, sin recuentos parciales.

    #1009 (incidencia en GitHub)
  • CambiadoFuncionascan-url-query incorpora vistas predefinidas (--preset, por ejemplo status_4xx,#1007

    title_missing, title_over_60, h1_missing, noindex_meta) que se combinan con AND con tus filtros, y --export PATH con --export-format csv|xlsx escribe todas las filas coincidentes en un archivo nuevo. La exportación se niega por encima de --export-max-rows (por defecto, 100 000) y nunca sobrescribe.

    #1007 (incidencia en GitHub)
  • CambiadoFuncionaLas reglas de elegibilidad de resultados enriquecidos pasan del código Python a…#1001

    Las reglas de elegibilidad de resultados enriquecidos pasaron del código Python a seohead/data/rich_results_rules.json, un archivo de datos versionado que se incluye con el paquete. El campo version de ese archivo es el valor que se graba como rules_version en cada veredicto de resultado enriquecido, así que cambiar una regla significa cambiar datos, no código.

    #1001 (incidencia en GitHub)
  • CambiadoFuncionaLos veredictos de resultados enriquecidos (check_schema y las comprobaciones de#1001

    evidencia estructurada guardada) ahora incluyen rules_version, de modo que cada resultado indica qué conjunto de reglas sin conexión lo produjo.

    #1001 (incidencia en GitHub)
  • CambiadoFuncionaDocumenta los seis scripts de mantenimiento y generación que no tenían referencia en la#997

    documentación…

    Documenta en docs/README.md los seis scripts de mantenimiento y generación que no tenían referencia en la documentación (scripts/generate_project_catalogue.py, generate_registry_inventory.py, render_readme_visuals.py, linux_lifecycle_smoke.py, capacity_watchdog.py, profile_million_audit.py): qué escribe cada uno y cuáles se ejecutan en CI (#997).

    #997 (incidencia en GitHub)
  • AñadidoFuncionaAñade la canalización del núcleo semántico como seohead/semantics, con base SQLite#995

    propia por proyecto…

    Añade la canalización del núcleo semántico como seohead/semantics, con su propia base SQLite por proyecto: seohead semantics <stage> --project DIR (init, import, collect, clean, graph, exact, cluster, competitors, synonyms, report, excel, mine, sitematch, relevance, status, export), las herramientas MCP seo_semantics_status, seo_semantics_run, seo_semantics_mine y seo_semantics_paid (las etapas de pago necesitan confirm_paid=true), la agrupación Louvain tras el nuevo extra semantics, la skill semantic-core empaquetada y un proyecto de ejemplo sintético. Los cargos del proveedor de una etapa semántica se etiquetan en el diario de gasto compartido (#995).

    #995 (incidencia en GitHub)
  • CambiadoFuncionaElimina el adaptador guiado de bot de Telegram seohead/integrations/bot; los recibos de#995

    entrega del monitor ahora viven en seohead/projects/service_delivery.py (#995).

    #995 (incidencia en GitHub)
  • CambiadoFuncionascan-url-query devuelve click_depth, la ruta interna más corta desde la página de#992

    inicio…

    scan-url-query devuelve click_depth, la ruta de enlaces internos más corta desde la página de inicio del escaneo, como columna, filtro y clave de orden. Las páginas que ningún enlace guardado alcanza son NULL (huérfanas). crawl_depth no cambia y sigue siendo la profundidad de la frontera, que es 0 para cada URL sembrada desde el sitemap. Un escaneo que no conservó sus enlaces falla con reason_code: click_depth_unavailable en lugar de informar un NULL falso. El valor se recalcula en cada consulta a partir de la tabla links; guardarlo como columna indexada al terminar el escaneo sigue pendiente, porque requiere decidir la versión del esquema (#992).

    #992 (incidencia en GitHub)
  • CambiadoFuncionascan-url-query y su herramienta MCP aceptan un argumento opcional facets (una lista#991

    de grupos…

    scan-url-query y su herramienta MCP aceptan un argumento opcional facets (una lista de ids de grupo, o all) que devuelve recuentos por grupo (status_2xx–5xx, title_missing, canonical_missing, directives_noindex/nofollow, with_outlinks) sobre los mismos filtros en una sola pasada. Los grupos que necesitan una proyección (interno o externo, sitemap, título duplicado o longitud, canonical propio o ajeno) todavía no están incluidos.

    #991 (incidencia en GitHub)
  • CambiadoFuncionaVinculaciones de fuentes del proyecto, primera entrega (#990): project-sources-link,#990

    project-sources-unlink y project-sources-list (CLI, más seo_project_sources_link|unlink|list en MCP) registran qué ids de recurso del proveedor usa un proyecto local en sources.json, junto a project.json. Solo sin conexión: sin descubrimiento, sin llamadas al proveedor y sin credenciales; project.json nunca se reescribe.

    #990 (incidencia en GitHub)
  • CambiadoFuncionaRastreo nativo: nueva comprobación IMG_BROKEN (#989, primera entrega) informa de destinos…#989

    Rastreo nativo: nueva comprobación IMG_BROKEN (#989, primera entrega) informa de los destinos de <img> que respondieron con 4xx/5xx, con la página de origen como evidencia. Lee el grafo de recursos guardado y se omite de forma explícita cuando no se midió ninguna imagen.

    #989 (incidencia en GitHub)
  • AñadidoFuncionaSe añade un clasificador puro de soft 404 sobre el cuerpo de página guardado#988

    (classify_stored_soft404): texto vacío, una frase de error en una página con poco contenido y una coincidencia de simhash con una plantilla de 404. Todavía no está conectado al rastreo y no emite incidencias; esta es la primera entrega de la incidencia #988.

    #988 (incidencia en GitHub)
  • CambiadoFuncionaLos rastreos nativos sondean los destinos de canonical y hreflang que ningún enlace#987

    alcanzó…

    Los rastreos nativos sondean, tras el rastreo y una vez por destino (5000 como máximo), los destinos de canonical y hreflang que ningún enlace alcanzó. Si un destino responde con 4xx/5xx o redirige, se informa CANONICAL_TARGET_ERROR, CANONICAL_TO_REDIRECT o HREFLANG_BROKEN_TARGET, igual que ya ocurría con los destinos rastreados (#987).

    #987 (incidencia en GitHub)
  • CambiadoFuncionaLas incidencias de cadena y bucle de redirección de un rastreo nativo ahora incluyen la#985

    ruta…

    Las incidencias de cadenas y bucles de redirección de un rastreo nativo ahora incluyen la ruta completa de saltos (details.path), para que una corrección pueda indicar cada salto que hay que sustituir. Ref. #985.

    #985 (incidencia en GitHub)
  • CambiadoFuncionaLas incidencias de cadena y bucle de redirección de un rastreo nativo ahora incluyen#985

    también…

    Las incidencias de cadenas y bucles de redirección de un rastreo nativo ahora incluyen también details.inbound_links (enlaces internos que aún apuntan a la primera URL de la cadena, con su texto ancla, limitado a 20) y inbound_links_count; sin un inventario all_inlinks, el campo es null con un motivo. Ref. #985.

    #985 (incidencia en GitHub)
  • CambiadoFuncionaLos proyectos pueden registrar un enlace a su núcleo semántico como datos introducidos#984

    por el operador (semcore_project, semcore_cluster_count, semcore_landing_mapping). El núcleo semántico sigue en su propia base de datos y no se fusiona con la del proyecto; la detección nunca escribe estos datos, y un dato aportado no puede declarar procedencia de detección. Documentado en docs/PROJECTS.md, en «Linking a semantic core» (parcial, #984).

    #984 (incidencia en GitHub)
  • CambiadoFuncionaEscritorio: la pantalla de grafo de enlaces sigue el diseño GraphFilters (lienzo y panel#975

    de filtros).

    El núcleo todavía no devuelve el grafo de enlaces completo, así que el lienzo muestra un estado de espera claro y los filtros permanecen inactivos hasta que lo haga (#975).

    #975 (incidencia en GitHub)
  • CambiadoFuncionaOAuth de GSC: provider-auth --action cancel (CLI) y seo_provider_auth action=cancel…#964

    OAuth de GSC: provider-auth --action cancel (CLI) y seo_provider_auth con action=cancel (MCP) cancelan un registro de flujo de consentimiento en el navegador que esté pendiente; status muestra el flujo pendiente cuando existe. El registro del flujo no guarda material de concesión y caduca a los diez minutos. Es la primera entrega de #964: todavía no hay inicio ni callback en el navegador, así que la superficie pública no crea ningún flujo y el acceso conectado sigue sin afirmarse nunca.

    #964 (incidencia en GitHub)
  • CambiadoFuncionacrawl-site --urls/--urls-file --project ahora registra el rastreo por lista de URL como#962

    una ejecución del observador (mode=list), de modo que aparece en project-observe y project-scans con su artefacto en la carpeta scans/ del proyecto. Un recolector que falla se registra como failed; el progreso y la reanudación de las ejecuciones por lista todavía no están cubiertos (#962).

    #962 (incidencia en GitHub)
  • AñadidoFuncionaAñade un esquema estructurado de playbooks: skill-list y scenario-list devuelven los#955

    pasos…

    Añade un esquema estructurado de los playbooks: skill-list y scenario-list devuelven los pasos ordenados de cada playbook, y skill-show y scenario-show añaden sus encabezados y pasos, para que un agente lea la forma del método sin analizar Markdown (#955). Nuevo comando CLI scenario-list y herramienta MCP seo_scenario_list.

    #955 (incidencia en GitHub)
  • CambiadoFuncionascan-content-search acepta --kind regex (MCP kind="regex") para buscar en#954

    documentos…

    scan-content-search acepta --kind regex (MCP kind="regex") para buscar en los documentos conservados con una expresión regular de Python. Las expresiones no válidas se rechazan antes de empezar la búsqueda; un documento que supera el presupuesto de tiempo de la regex se informa como no disponible, nunca como ausente.

    #954 (incidencia en GitHub)
  • CambiadoFuncionaLas llamadas a DataForSEO cuya respuesta se pierde (error de red tras enviar la petición)#949

    se registran con cost_unknown y charge_status: unknown, de modo que spend-report las muestra como inciertas en lugar de contarlas como una llamada medida de coste cero (#949).

    #949 (incidencia en GitHub)
  • AñadidoFuncionaNuevo comando scan-structured-blocks (CLI) y herramienta MCP#948

    seo_scan_structured_blocks: para una URL conservada, describe cada bloque JSON-LD (su línea de origen, estado valid / errors / warnings / parse_error, tipos, una lista plana de propiedades, JSON de origen acotado y errores del grafo de Schema.org). Funciona sin conexión, solo sobre el cuerpo completo de la página conservado; no hace peticiones de red ni cambia artefactos.

    #948 (incidencia en GitHub)
  • CambiadoFuncionacrawl-site sin proyecto que escribe un artefacto de escaneo SQLite ahora comparte su#942

    límite por host…

    crawl-site sin proyecto que escribe un artefacto de escaneo SQLite ahora comparte su límite de peticiones por host con otros rastreos simultáneos del mismo host, mediante una programación privada en la carpeta de estado del usuario (~/.config/seohead/.origin-pacing.sqlite). Antes, los rastreos sin proyecto se ejecutaban sin control de ritmo entre procesos.

    #942 (incidencia en GitHub)
  • CambiadoFuncionaPerfiles de crawl-site (#941): crawl-profile list muestra los nombres de perfil#941

    guardados y crawl-profile delete NAME elimina uno; ambos devuelven JSON y rechazan los nombres desconocidos mostrando la lista de perfiles guardados.

    #941 (incidencia en GitHub)
  • CambiadoFuncionaPerfiles de crawl-site (#941): --save-profile NAME --config FILE guarda una#941

    configuración de rastreo validada como perfil con nombre (se rechaza si incluye cabeceras de credenciales); --profile NAME rastrea con él, y --set sigue aplicándose encima. Los perfiles se guardan en ~/.config/seohead/crawl-profiles o en la carpeta indicada por SEOHEAD_CRAWL_PROFILES. Listar y borrar perfiles no forma parte de esta entrega.

    #941 (incidencia en GitHub)
  • CambiadoFuncionacompare.v1 ahora enumera las páginas rastreadas en un solo lado (url_sets:#938

    only_in_before…

    compare.v1 ahora enumera las páginas rastreadas solo en un lado (url_sets: only_in_before, only_in_after y recuentos). Cuando alguno de los dos rastreos es parcial, url_sets.unproven es true, de modo que la ausencia no se presenta como prueba.

    #938 (incidencia en GitHub)
  • CambiadoFuncionaLos saltos de cadena de redirección y canonical registran el estado de cada salto, el#930

    siguiente Location…

    Los saltos de las cadenas de redirección y de canonical registran el estado de cada salto, la siguiente Location (redirects) y el tiempo de respuesta, de modo que la cadena de una URL se lee desde la evidencia guardada sin otra petición (#930).

    #930 (incidencia en GitHub)
  • CambiadoFuncionaLos bucles de redirección en cadenas por URL terminan con un paso marcador ({"url": ..., "loop": true}#930

    )…

    Los bucles de redirección en las cadenas por URL terminan con un paso marcador ({"url": ..., "loop": true}) que no se vuelve a solicitar, de modo que la URL repetida queda visible en la evidencia guardada; final_url sigue apuntando al último salto obtenido (#930).

    #930 (incidencia en GitHub)
  • AñadidoFuncionaExpone en CLI y MCP los pasos de creación e ingesta de escaneos del registro de#926

    remediación: remediation-create / seo_remediation_create crea un registro nuevo y vacío vinculado a un proyecto (producer_build debe ser un SHA de Git completo de 40 caracteres; las rutas existentes se rechazan), y remediation-ingest / seo_remediation_ingest ingiere una auditoría guardada como línea base o histórico sin volver a lanzar un rastreo (la reingesta de la misma revisión es idempotente). La lógica de almacenamiento no cambia; esta es la primera entrega de #926.

    #926 (incidencia en GitHub)
  • CambiadoFuncionacrawl_site y las ejecuciones de escaneo informan effective_max_requests_per_second y#925

    warnings: un aviso cuando la tasa efectiva supera 2 req/s (el umbral es estrictamente mayor que 2). La CLI muestra el mismo aviso en stderr; el JSON de stdout y los valores por defecto no cambian. El control de ritmo no se ha tocado.

    #925 (incidencia en GitHub)
  • CambiadoFuncionaRegistro estructurado de eventos del proyecto (events.jsonl): eventos de solo adición#923

    con origen, actor y texto acotado, que se leen del más reciente al más antiguo, por páginas, con filtros de origen y de texto. Se exponen como project-event-append y project-event-page en la CLI, y como seo_project_event_append y seo_project_event_page en MCP (issue #923).

    #923 (incidencia en GitHub)
  • AñadidoFuncionaAñade el comando ai-column y la herramienta MCP seo_ai_column, la primera entrega de

    la columna personalizada con IA (ref. #1012). Sobre páginas de escaneo conservadas y seleccionadas, o sobre elementos normalizados que se aporten, prepara un plan acotado a partir del título, los encabezados y un extracto del texto, con una estimación de tamaño basada en caracteres (sin precio aplicado) y el alcance de consentimiento que el agente que llama debe respetar antes de cualquier transferencia. Los valores por URL que se aportan se validan contra el hash de origen de cada página; los valores ausentes, obsoletos, vacíos o demasiado grandes se informan como tales y nunca se rellenan. Un CSV opcional, a prueba de fórmulas, exporta la columna. SEOHEAD no guarda ninguna clave de proveedor ni hace llamadas a modelos.

  • CambiadoFuncionaComparte los abridores SQLite de solo lectura y de escritura en seohead.core.sqlite.

    Los lectores de almacenamiento, el importador de escaneos, el archivo de GSC, el almacén de fuentes, el almacén de unión de evidencias y las dos clases de comprobaciones ahora abren sus bases de datos mediante un único auxiliar para conexión, row factory y PRAGMAs. Las dos clases de comprobaciones cierran sus conexiones de forma explícita. El comportamiento no cambia; la normalización de rutas y el orden de los PRAGMA se mantienen en cada punto de llamada.

  • CambiadoFuncionaCorrecciones tras una revisión de comprobaciones, fuentes de datos e importación de

    evidencias.

    Cambios de comportamiento intencionados en estas rutas: - Las cadenas de redirección de exactamente el límite de saltos (por defecto, 20) ahora se resuelven en lugar de informarse como no resueltas. La comprobación de bucles se ejecuta antes que la de límite, tanto en la resolución de cadenas como en los recorridos de la ruta de saltos. - Las comprobaciones de confianza y de citas de EEAT comparan los hosts de destino con su puerto (netloc), igual que la lógica de host de los enlaces internos. Los sitios con puertos explícitos pueden cambiar sus resultados. - Las comprobaciones de palabras clave de llms.txt buscan los términos ASCII como palabras completas, con plural opcional, así que rapid, Showcase y Toolbar ya no pasan. Las raíces cirílicas siguen coincidiendo como subcadenas. - La captura de navegación asigna el motivo reload a refresh_navigation. Los motivos solicitados sin asignar, como pageBlockInterstitial, se registran como observaciones de frame que el validador acepta. - La detección de tecnologías trata una implicación negada (["not", X]) como si no implicara nada. - La importación de evidencias rechaza los nombres de métrica declarados duplicados, y el descubrimiento en Search Console usa las filas que recibe. - Los reintentos de Yandex Cloud solo esperan entre intentos. Los reintentos de analítica de consultas de Yandex Webmaster esperan antes del siguiente intento. - La construcción del schema pasa su timeout al cliente HTTP (por defecto, sin cambios). - El almacén de recibos de entrega se crea con modo 0600 antes de que SQLite lo abra. - Las ejecuciones del grafo semántico se serializan, porque el conjunto de stop words es estado del módulo. El ejecutor semántico informa de los errores de SQLite como ok: false en lugar de lanzar excepciones. - El analizador de errores de CrUX tolera cuerpos de respuesta que no son objetos. - Se eliminó una guarda sqlite3 is None inalcanzable en el registro.

  • CambiadoFuncionaEscritorio: una pantalla de Backlinks con el diseño v2.

    Muestra un estado de espera claro hasta que el núcleo guarde un perfil de enlaces del proyecto (#999); sin filas de ejemplo, y los filtros de grupo están desactivados con el mismo motivo.

  • CambiadoFuncionaPantalla Crawler de escritorio: añade el banner de resultados temporales con la dirección

    seleccionada y el texto de estado (solo se muestra cuando un rastreo sin proyecto devuelve resultados), mueve las acciones de limpiar y guardar como proyecto a un menú de desbordamiento por debajo de 1000 px, mantiene usables el campo de dirección y la tira de pestañas de comprobación en anchos estrechos, desplaza la cabecera de resultados en lugar de comprimir sus columnas, y da a la barra de estado de la aplicación el mismo relleno derecho de 8 px en los temas oscuro y claro.

  • CambiadoFuncionaEscritorio: pantalla de estados fatales por lienzo ErrorsCore: falta el núcleo, poco

    espacio…

    Escritorio: pantalla de estados fatales por lienzo ErrorsCore: el núcleo ausente, el poco espacio en disco y la falta de acceso de escritura se muestran a partir de hechos reales; la versión del núcleo y la integridad del escaneo muestran la píldora neutral «unavailable in this core version» hasta que el núcleo las informe.

  • CambiadoFuncionaEscritorio: el menú de fila de URL y el de cabecera de columna, los grupos de la barra de

    menús Edit, Scan y Window, y los menús contextuales de incidencias y tareas siguen el tablero Menus del lienzo. Las entradas que el núcleo todavía no ofrece permanecen visibles y desactivadas, con el motivo en el tooltip.

  • CambiadoFuncionaEscritorio: la pantalla «Export and reports» sigue el lienzo de diseño ProjExport

    (conjunto de datos…

    Escritorio: la pantalla «Export and reports» sigue el lienzo de diseño ProjExport (elección de conjunto de datos y de formato, tarjeta de carpeta, exportaciones recientes). Los conjuntos de datos y formatos que el núcleo todavía no puede exportar (comparación, tareas, PDF) se muestran como no disponibles; el botón de ejecutar permanece desactivado hasta que se conecte la exportación (#1191).

  • CambiadoFuncionaNeutraliza TAB y CR iniciales en los identificadores del inventario de marketing y en los

    CSV de revisión de borradores de meta descripción, con el mismo prefijo de apóstrofo que ya se aplica a =, +, - y @. Ambas protecciones comparten ahora seohead.core.tabular.neutralize_formula.

  • CambiadoFuncionaPeticiones a proveedores con credenciales (Arsenkin, Metrika, Yandex Cloud, IndexNow…

    Las peticiones a proveedores que llevan credenciales (Arsenkin, Metrika, Yandex Cloud, IndexNow, Topvisor y destinos de BI) ya no siguen redirecciones HTTP, así que la cabecera Authorization nunca se vuelve a enviar a otro host. Ahora, una redirección aparece como error HTTP del proveedor.

  • AñadidoFuncionaAñade el formato de redirecciones csv (filas source,target,301, entre comillas si

    hace falta) a generate_rule y a la ayuda de la CLI de redirects-generate. El formato wordpress-redirection no se incluye, porque su sintaxis de importación aún no está verificada (#998).

  • CambiadoFuncionaEl diario de ejecuciones (runs.jsonl) ahora rota al superar un límite de tamaño (5 MiB

    por defecto; SEOHEAD_RUN_LOG_MAX_BYTES lo cambia). La generación anterior se guarda como runs.jsonl.1, y las lecturas cubren ambos archivos, así que las búsquedas de reutilización siguen viendo las llamadas recientes.

  • CambiadoFuncionaDistribuye la pestaña Schema de la tarjeta de URL del escritorio según la estructura de

    lienzo de design-v2 (lista de bloques, árbol de bloques, comprobaciones). El núcleo solo devuelve recuentos de bloques JSON-LD por URL, así que las columnas muestran estados de espera honestos vinculados a la incidencia 948 del núcleo, y los recuentos conocidos siguen siendo reales; no se muestran bloques de ejemplo.

9 de octubre de 2026

4 añadido4 cambiado
  • AñadidoFuncionaAñade etiquetas de terminal en RU/EN según el idioma, un bloque de progreso del escaneo#951

    actual, selección explícita de escaneo y una salida compacta del observador.

    #951 (incidencia en GitHub)
  • CambiadoFuncionaLos escaneos guardados se abren ligeramente para lectura (#931).#931

    scan-status, scan-url-detail, scan-link-inspect y el observador de proyecto (project-scans, project-observe) ya no validan todo el artefacto en cada apertura: comprueban identidad, esquema, versión y la fila de cabecera, toman los contadores de SQL (GROUP BY sobre pages_status) y lo indican en un campo validation aditivo ("light" o "full"). La validación completa se ejecuta cuando la pides (full_validation: true en scan-status, o --input '{"input_path": "...", "full_validation": true}' en la CLI) o cuando los mismos bytes (ruta, tamaño, mtime, estado de WAL, hash de cabecera) ya se validaron por completo en el proceso. Un escaneo que no supera las comprobaciones ligeras se rechaza con el mismo error de antes, y cada vía que escribe o registra evidencias sigue validando por completo. scan-url-detail ejecuta la búsqueda del destino de redirección (sin índice en responses.effective_url_id) con un presupuesto de 0,5 s y marca responses.redirect_target_lookup como skipped en lugar de recorrer una tabla grande.

    #931 (incidencia en GitHub)
  • AñadidoFuncionaAñade estado MCP compartido y auditado, con revocación al arrancar y en vivo de llamadas#929

    a herramientas; expone la presencia segura de los clientes mediante la CLI.

    #929 (incidencia en GitHub)
  • AñadidoFuncionaAñade registro de clientes con permiso explícito, previsualizaciones, escrituras#929

    atómicas, copias de seguridad verificadas y restauración segura frente a conflictos.

    #929 (incidencia en GitHub)
  • AñadidoFuncionaAñadido scan-url-query (MCP seo_scan_url_query): lectura filtrada y paginada de solo#927

    lectura…

    Añadido scan-url-query (MCP seo_scan_url_query): lectura de solo lectura, filtrada, ordenada y paginada en el servidor, de toda la tabla de páginas de un escaneo guardado. Devuelve total, filtered_total (null más filtered_total_state: capped cuando el recuento supera su presupuesto de tiempo), una proyección de columnas, etiquetas de cobertura del escaneo, el formato seohead.scan-url-query.v1 y un reason_code legible por máquina en cada error. Como máximo 200 filas por llamada; ordenar por url, status_code, page_ordinal o url_id usa índices, y cualquier otra columna necesita un filtro que deje como máximo 100 000 filas (si no, sort_not_indexed). El escaneo se abre con una comprobación ligera de identidad y de generación de esquema, no con validación completa, y nunca se modifica.

    #927 (incidencia en GitHub)
  • CambiadoFuncionascan-link-inspect --view links (MCP seo_scan_link_inspect) pagina los enlaces#924

    salientes o entrantes de una URL, buscada por dirección y no por ID de documento: ancla, rel con las marcas nofollow/sponsored/ugc, interno o externo, posición guardada, atributo target y el código HTTP del otro extremo (null cuando esa página no se escaneó). Filtra por tipo de enlace, seguimiento, clase de estado y subcadena; offset/limit hasta 200; total/filtered_total son exactos o están marcados como capped. El escaneo se abre en solo lectura sin validación completa, y los fallos incluyen un reason_code legible por máquina (url_not_found, scan_not_available, url_not_scanned, links_not_retained). Las vistas y los campos existentes no cambian.

    #924 (incidencia en GitHub)
  • CambiadoFuncionaReorganiza el diseño de paquetes, sin capas de compatibilidad: seohead.servers pasa a

    ser seohead.mcp, seohead.tools pasa a ser seohead.checks, seohead.bot y seohead.remote_api se mueven bajo seohead.integrations, la CLI vive en el paquete seohead.cli (con seohead.cli.terminal_progress), los módulos raíz compartidos (models, graph, filesystem, runlog, verification, canonical_policy, input_contracts, job_contracts, provider_matrix) pasan a seohead.core, y la procedencia de la compilación pasa a seohead._build.provenance. examples/ y config.example.json se mueven a docs/examples/; PROVENANCE.md y TRADEMARKS.md se mueven a docs/legal/. Los comandos seohead y sf-analyzer no cambian; las importaciones de Python con las rutas antiguas deben actualizarse.

  • CambiadoFuncionaReescribe el README en torno a la instalación, tres rutas de inicio rápido (del rastreo

    nativo al informe, exportaciones sin conexión de Screaming Frog, proyecto más agente), un mapa de funciones por área, un resumen de la CLI, la configuración de MCP para Claude Code y Claude Desktop, la app de escritorio complementaria y el límite entre lo medido y lo no medido, con capturas reales de terminal en docs/assets/ tomadas de un fixture de QA local y del fixture de exportación sintético. Añade docs/CLI.md, que agrupa cada comando registrado por tarea con sus anotaciones de red, escritura y pago (una prueba de desfase ahora falla si falta un comando), y docs/WORKFLOWS.md, que documenta los comandos de workflow-run, bandeja de entrada y registros de monitor, que antes solo se mencionaban como referencia.

8 de octubre de 2026

1 añadido10 cambiado1 corregido
  • CorregidoFuncionaMantiene el cómputo de bytes de HTML/DOM retenido dentro de la transacción e incremental,#914

    en…

    Mantiene el cómputo de bytes de HTML/DOM retenido dentro de la transacción y de forma incremental, en lugar de volver a recorrer todos los cuerpos guardados por cada respuesta única. Los escritores reabiertos reconstruyen el contador una sola vez; la deduplicación, el rollback, los savepoints y los límites de retención de cuerpos siguen intactos.

    #914 (incidencia en GitHub)
  • CambiadoFuncionaLos informes de BI mantienen como desconocidos los estados de recopilación de proveedores#833

    no verificados y las marcas de calidad en métricas, cobertura y manifiestos; el muestreo, el umbral o el truncado confirmados se marcan como parciales. Las cohortes búsqueda frente a sesiones exigen calidad de recopilación explícita, medidas de recuento no negativas y ámbitos de fuente cualificados, y conservan la identidad de fuente de cada eje, la atribución, el ámbito de búsqueda y la política de calendario. El paquete sintético de informes sigue funcionando sin conexión; la aceptación nativa en Sheets y Looker sigue siendo un trabajo aparte.

    #833 (incidencia en GitHub)
  • CambiadoFuncionaLos escaneos de sitio SQLite nativos aceptan max_urls=0 para recopilar hasta vaciar la#818

    cola, y max_depth=-1 para desactivar el límite de profundidad. Los presupuestos de tiempo y HTTP siguen siendo configurables por separado, las protecciones de almacenamiento y la interrupción con reanudación siguen activas, y las rutas materializadas heredadas rechazan una población de URL sin límite.

    #818 (incidencia en GitHub)
  • CambiadoFuncionaLos escaneos solo de sitemap también conservan el límite de URL desactivado, en lugar de#818

    rechazar su primer miembro declarado cuando el límite configurado es cero.

    #818 (incidencia en GitHub)
  • CambiadoFuncionaLas tasas de petición finitas explícitas por encima de las 2 peticiones/s predeterminadas#818

    ahora llegan también al carril compartido de ritmo por origen del proyecto, además del limitador por escaneo. Los escaneos en paralelo reservan una única programación común por host, en lugar de multiplicar su tasa.

    #818 (incidencia en GitHub)
  • CambiadoFuncionaInterrumpir el análisis nativo devuelve ahora un resultado interrumpido, explícito y#754

    reanudable, y conserva las páginas capturadas en lugar de mostrar un traceback de KeyboardInterrupt.

    #754 (incidencia en GitHub)
  • CambiadoFuncionaRegenera el catálogo de proyectos empaquetado tras la actualización del escenario del#754

    proveedor Bing.

    #754 (incidencia en GitHub)
  • CambiadoFuncionaRechaza las filas de respuesta mal formadas de Bing Webmaster en lugar de informar un#753

    resultado vacío completo. Conserva los datos de respuesta sin procesar, las filas de origen y los recuentos exactos devueltos en la evidencia guardada del proveedor. Las respuestas de recuento de enlaces mantienen su envoltorio de página documentado e informan de las poblaciones de varias páginas como parciales cuando solo se recopiló una de las páginas solicitadas.

    #753 (incidencia en GitHub)
  • CambiadoFuncionaReconoce el fallback compartido y ya existente de cuenta de servicio de Google en la#753

    preparación y el descubrimiento de credenciales del proveedor GA4. Los permisos de cuenta y el acceso al destino siguen sin verificar, las credenciales mal formadas se informan de forma explícita, y se mantiene el soporte de bearer OAuth sin exigir ambas fuentes.

    #753 (incidencia en GitHub)
  • CambiadoFuncionaVincula las referencias de capacidades headless con el aislamiento de ejecución nativo y#743

    el límite público de enrutamiento del rastreo externo, distinguiendo la implementación interna de la disponibilidad en CLI/MCP, sin cambiar el comportamiento del rastreo ni las afirmaciones de capacidad.

    #743 (incidencia en GitHub)
  • AñadidoFuncionaAñade paginación acotada de ejecuciones terminadas a project-observe en CLI y MCP, sin

    ocultar…

    Añade paginación acotada de ejecuciones terminadas a project-observe en CLI y MCP, manteniendo visible cada registro en ejecución almacenado. Las páginas conservan los ID de ejecución exactos y el orden inverso de admisión; los recuentos y los metadatos de retención describen el almacén actual de 100 registros, no el historial completo. La lectura nunca cambia los estados de ejecución guardados. Las entradas JSON de la CLI conservan su paginación y su ámbito de proyecto, salvo que un flag con nombre explícito los sobrescriba.

  • CambiadoFuncionaGestiona Ctrl+C en todo el traspaso nativo posterior a la recopilación, incluida la

    apertura del escaneo guardado, las fases opcionales de seguimiento, el análisis y la finalización. Las capturas sin terminar conservan sus datos y su punto de control reanudable, y devuelven un resultado JSON interrumpido y explícito. Una interrupción tras el commit final conserva el artefacto completado e informa de su disponibilidad real de auditoría. La reanudación explícita completa el trabajo pendiente posterior a la recopilación aunque la cola de URL esté vacía, conservando los flags existentes de omisión de evidencias y los insumos de sitemap retenidos.

7 de octubre de 2026

4 añadido4 cambiado1 corregido
  • AñadidoFuncionaAñade un fixture desechable de aceptación en Linux para la ejecución real de workers SSH#754

    con clave, las descargas de API y TLS autenticadas y el ENOSPC del worker nativo en un tmpfs acotado solo para trabajos. Conserva la cola y la evidencia, y exige un resultado explícito de no éxito, sin reintentos, antes de un nuevo trabajo de recuperación JS. Aclara la diferencia entre las mediciones locales del ciclo de vida y la evidencia de SSH y de contención del sistema operativo.

    #754 (incidencia en GitHub)
  • CambiadoFuncionaConserva la evidencia parcial de JavaScript en los resultados de trabajos remotos,#754

    incluida la corrección de solo lectura de trabajos antiguos terminados, sin cambiar los artefactos guardados ni los presupuestos de renderizado. Verifica la copia de seguridad y restauración reales de la cola mediante estado autenticado, descargas e idempotencia persistente; mantiene el fixture de recuperación de dos páginas con renderizado completo dentro de sus presupuestos finitos existentes.

    #754 (incidencia en GitHub)
  • CambiadoFuncionaDevuelve el código de salida 130 sin traceback cuando SIGINT interrumpe la salida JSON

    final tras…

    Devuelve el código de salida 130 sin traceback cuando SIGINT interrumpe la salida JSON final después de que un manejador haya terminado. Los artefactos guardados no cambian; un flujo de salida truncado nunca se informa como exitoso.

  • AñadidoFuncionaRegistra la estrategia de área de contenido usada para generar los hashes y recuentos de

    tokens guardados, en lugar de la estrategia de área por defecto del parser. Los selectores explícitos y las exclusiones tienen ahora una procedencia de extracción coincidente, incluso cuando el parser de la página usó su región por defecto.

  • CorregidoFuncionaMantiene los archivos de preparación SQLite nativos no publicados fuera del historial de

    escaneos y de los candidatos de retención; sigue informando de los archivos publicados no válidos y permite los escaneos ocultos normales que nombra el usuario.

  • AñadidoFuncionaAñadida la recopilación SQLite nativa solo de sitemap: un sitemap explícito define la

    población completa de URL solicitada, sin respaldo en la página de inicio, sin expansión de hipervínculos ni expansión de destinos de redirección. Las poblaciones de sitemap vacías, incompletas o que superan el presupuesto se detienen de forma explícita, y la reanudación reutiliza la población retenida sin volver a descargar el XML.

  • CambiadoFuncionaConserva registros de ejecución de proyecto distintos para capturas nativas simultáneas y

    comparte…

    Conserva registros de ejecución de proyecto distintos para las capturas nativas simultáneas y comparte, dentro del proyecto, una puerta de envío de 2 peticiones/s para el mismo host público; expone a los observadores el tipo de origen de cada ejecución, su procedencia, la huella de configuración y el límite de tasa agregado.

  • AñadidoFuncionaAñade búsqueda literal sin conexión sobre HEAD, HTML, texto del cuerpo y marcado

    seleccionado por CSS guardados, con cobertura estática o renderizada explícita, cuerpos ausentes desconocidos, fragmentos opcionales redactados y paginación con verificación de integridad para los nuevos paquetes de resultados locales.

  • CambiadoFuncionaConserva la configuración propia de un rastreo guardado de Screaming Frog al exportarlo:

    load-crawl ya no inyecta la configuración actual del spider. Los rastreos en vivo de spider y de lista siguen recibiendo sus perfiles explícitos por ejecución.

6 de octubre de 2026

9 añadido14 cambiado9 corregido
  • CambiadoFuncionaHace que las pruebas de captura externa propias resuelvan de forma coherente sus hosts#896

    virtuales de loopback en todos los sistemas operativos, sin cambiar la política de red de producción.

    #896 (incidencia en GitHub)
  • CorregidoFuncionaMantiene la entrada de terminal funcionando por encima del límite de descriptores de#896

    select, e impide que Delete o las secuencias de control no compatibles cancelen notas sin guardar.

    #896 (incidencia en GitHub)
  • CambiadoFuncionaConserva eventos de navegación del navegador con versión y omisiones acotadas, estado de#826

    la captura, política del renderizador y procedencia de URL. Distingue las redirecciones HTTP observadas, la navegación por script, historial o fragmento de Chromium y las causas desconocidas, sin afirmar clics humanos.

    #826 (incidencia en GitHub)
  • AñadidoFuncionaExpone la misma evidencia mediante render-check y los informes acotados y sin conexión de#826

    scan-navigation; conserva las observaciones parciales cuando el renderizado falla.

    #826 (incidencia en GitHub)
  • CambiadoFuncionaMantiene la compatibilidad con rollback conservando la evidencia de navegación dentro de#826

    los ajustes extensibles del renderizador; valida la codificación de la prerelease anterior sin debilitar las comprobaciones de procedencia ni tratar los eventos observados como política del renderizador.

    #826 (incidencia en GitHub)
  • CorregidoFuncionaMantiene las poblaciones de resumen anidadas grandes, incluidos los histogramas de#818

    profundidad, en los complementos PDF completos, sin cargarlas al presupuesto acotado de metadatos de visualización. Conserva los destinos con nombre, los esquemas y los enlaces internos al reescribir los enlaces portátiles del complemento, clonando el documento PDF completo.

    #818 (incidencia en GitHub)
  • AñadidoFuncionaAñade pdf_policy="overview-v1" explícito para las solicitudes PDF de audit.v2 retenidas.#818

    La primera página distingue el origen completo, los recuentos mostrados y los omitidos; los prefijos de visualización deterministas conservan los estados y motivos de cobertura completos y enlazan con el JSON de auditoría completo en streaming y con los complementos CSV de hallazgos, páginas y ámbito. Un manifiesto de hashes y recuentos registra la procedencia y los límites de recursos. Los destinos existentes se rechazan, las exportaciones se preparan por etapas, y el marcador de finalización del PDF se publica solo cuando todos los complementos obligatorios se validan. El comportamiento por defecto del PDF no cambia: el resumen nunca se selecciona en silencio ni se describe como un PDF exhaustivo. Consulta docs/PDF_OVERVIEW.md para ver los límites exactos y la semántica ante fallos.

    #818 (incidencia en GitHub)
  • AñadidoFuncionaAñade la operación de solo lectura page_views del proveedor GA4 para recuentos de#782

    vistas por fecha, nombre de host y ruta visitada, de forma independiente de las sesiones de páginas de entrada. Reutiliza las credenciales, el transporte y el lector de informes paginados existentes de GA4, con reintentos acotados, resultados de cuota y permisos, metadatos explícitos de zona horaria, muestreo y umbral, y vinculación de URL con el origen declarado. La evidencia restringida del proveedor guardada se normaliza mediante la unión y el pipeline de BI existentes; el tráfico ausente sigue siendo no disponible en lugar de convertirse en cero.

    #782 (incidencia en GitHub)
  • CorregidoFuncionaMantiene acotadas las actualizaciones del observador reutilizando la cobertura por sitio#777

    y proyectando…

    Mantiene acotadas las actualizaciones del observador reutilizando la cobertura por sitio, proyectando la actividad de los colectores en vivo por separado y paginando los hallazgos de audit.v2 sin materializar colecciones del grafo no relacionadas.

    #777 (incidencia en GitHub)
  • CambiadoFuncionaConserva cada colector activo en un historial acotado y publica ventanas de contadores#777

    medidos…

    Conserva cada colector activo en un historial acotado, publica ventanas de contadores medidos con marca de tiempo y distingue los contadores no medidos de cero. Transmite el progreso verificado de Screaming Frog acotando ambos canales de diagnóstico.

    #777 (incidencia en GitHub)
  • AñadidoFuncionaAñade páginas de solo lectura para la lista de comprobaciones, el detalle de tareas y los#777

    escaneos retenidos, además de un ámbito explícito de métodos aplicables y una proyección de la bandeja de entrada más reciente.

    #777 (incidencia en GitHub)
  • CorregidoFuncionaMantiene diferenciadas las ejecuciones de sitemap asociadas explícitamente: los#777

    contadores en curso siguen desconocidos, y las mediciones finales cuentan por separado los documentos de sitemap analizados frente a las URL declaradas, los errores y los truncados.

    #777 (incidencia en GitHub)
  • CambiadoFuncionaObserva los recibos de artefactos de la lista de comprobaciones mediante metadatos de#777

    identidad de…

    Observa los recibos de artefactos de la lista de comprobaciones mediante metadatos protegidos de identidad de archivo, sin recalcular el hash de los bytes guardados al actualizar. Las lecturas explícitas de cobertura mantienen la verificación byte a byte; la evidencia cambiada o heredada y no verificada sigue visible como obsoleta o no verificada.

    #777 (incidencia en GitHub)
  • CorregidoFuncionaMantiene los recibos históricos de prioridad vinculados a su ámbito original de elementos#777

    cuando se añaden tareas tras la preparación, y valida cada candidato de cobertura completo antes de la publicación atómica. Las lecturas de detalle de competidores con ámbito conservan la verificación pasiva de solo metadatos.

    #777 (incidencia en GitHub)
  • AñadidoFuncionaAñade comparación explícita de auditorías guardadas en disco, con resultados NDJSON#762

    completos, orden determinista, identidades de origen, sumas de comprobación por archivo y conservación de hallazgos antes y después. Las comparaciones grandes de audit.v2 requieren un nuevo directorio de salida; las identidades duplicadas y las colisiones en la correspondencia de URL fallan en lugar de perder filas.

    #762 (incidencia en GitHub)
  • CorregidoFuncionaMantiene acotada la verificación dirigida de audit.v2 cuando hay filas duplicadas,#762

    conserva la identidad de escaneo validada en los documentos seleccionados y rechaza las identidades en conflicto o los rastreos posteriores no válidos como prueba de corrección.

    #762 (incidencia en GitHub)
  • AñadidoFuncionaAñade compresión gzip en streaming opcional para los archivos NDJSON completos de#762

    compare.v2, con bytes comprimidos deterministas y hashes exactos de los comprimidos con recuentos decodificados de filas y bytes. Añade un lector acotado que valida exportaciones planas o gzip y rechaza los flujos dañados o los recuentos de manifiesto que no coinciden; la salida plana sigue siendo el valor por defecto.

    #762 (incidencia en GitHub)
  • CorregidoFuncionaMantiene la compatibilidad de comparación de corpus guardados como desconocida si falta#762

    cualquiera…

    Mantiene la compatibilidad de comparación de corpus guardados como desconocida cuando falta alguno de los dos indicadores de completitud, y advierte explícitamente de los corpus parciales conocidos. Conserva los ID y motivos de las comprobaciones omitidas y desactivadas junto con las diferencias de hallazgos, para que las mediciones ausentes no puedan presentarse como corrección verificada.

    #762 (incidencia en GitHub)
  • CambiadoFuncionaHace que el observador de proyecto de terminal permita explorar detalles legibles de#752

    tareas, métodos, datos estructurados, escaneos, ejecuciones, bandeja de entrada y evidencia guardada, con páginas acotadas y cobertura de ámbito honesta. Las lecturas de almacenamiento y los envíos explícitos de notas se mantienen fuera del bucle de entrada.

    #752 (incidencia en GitHub)
  • CambiadoFuncionaConserva borradores de notas y de objetivos por separado durante una sesión, admite#752

    edición con cursor, conserva los pegados grandes sin truncar, muestra los recibos de guardado en todos los diseños e imprime los borradores no guardados al salir normalmente de la terminal para poder recuperarlos.

    #752 (incidencia en GitHub)
  • AñadidoFuncionaAñade exploración explícita de cobertura y artefactos del sitio propio y de competidores…#752

    Añade exploración explícita de cobertura y artefactos del sitio propio y de los competidores, conserva el sitio seleccionado al pasar por las páginas de escaneo y hallazgos, muestra sugerencias recientes de competidores basadas en notas, y mantiene visible el progreso de recopilación medido en terminales compactas. Las muestras obsoletas ya no se animan como progreso en vivo.

    #752 (incidencia en GitHub)
  • AñadidoFuncionaAñade un inventario versionado de capacidades headless generado a partir de la#743

    configuración real del rastreador, con referencias a implementación, CLI/MCP, pruebas y brechas de aceptación explícitas.

    #743 (incidencia en GitHub)
  • AñadidoFuncionaAñade un benchmark opcional de HTML/JavaScript en un origen propio, con fases congeladas,#743

    memoria del árbol de procesos, presupuestos de disco y de recuperación. Los navegadores reales crean los DOM medidos; el perfil no establece por sí mismo la capacidad de JavaScript para sitios grandes.

    #743 (incidencia en GitHub)
  • CorregidoFuncionaCorrige el argumento de streaming no soportado del puente JavaScript nativo y conserva#743

    los contadores de renderizado ya observados durante la cancelación controlada y la reanudación.

    #743 (incidencia en GitHub)
  • CambiadoFuncionaPermite que log-scan consuma rutas de escaneo nativas guardadas y complementos audit.v2#711

    sin materializar JSON heredado. Procesa en streaming los hallazgos de consistencia, mantiene en disco la pertenencia a páginas nativas y la deduplicación de hallazgos, conserva los recuentos exactos de anomalías y limita solo los ejemplos. Informa explícitamente de que falta la traza nativa de decisiones de exclusión.

    #711 (incidencia en GitHub)
  • CambiadoFuncionaReconoce un hallazgo de lastmod de sitemap de todo el sitio en el origen raíz de su sitio#711

    medido cuando no se rastreó la página de inicio. La excepción requiere evidencia de resumen de sitemap coincidente y no exime los hallazgos de página, los hosts no relacionados ni las rutas de destino no compatibles.

    #711 (incidencia en GitHub)
  • CambiadoFuncionaCompara escaneos audit.v2 guardados mediante una clave exacta y un índice ordinal, sin

    duplicar las cargas de páginas y hallazgos en el almacenamiento SQLite temporal. Las filas completas, las exportaciones deterministas planas o gzip, las identidades de origen y las entradas heredadas siguen siendo compatibles. Los lectores de auditoría fijan la instantánea validada mediante lecturas indexadas de filas.

  • CambiadoFuncionaRevertir los miembros de salida de comparación propios ante un fallo tardío de

    publicación y rechazar destinos añadidos en paralelo…

    Revierte los miembros de salida de comparación propios si la publicación falla tarde y rechaza los destinos añadidos en paralelo; el manifiesto sigue siendo la marca final de confirmación del paquete.

  • CambiadoFuncionaHacer que la entrada pública describa la ingeniería SEO configurable con agentes y enlace

    toda la superficie de capacidades a sus métodos, entradas y límites de evidencia. Corregir la guía obsoleta sobre nativo/SF, cobertura de proyectos y remediación; documentar por separado el libro de trabajo para desarrolladores redactado por el agente frente a la salida factual del informe, incluidos los criterios de aceptación revisados y los enlaces a las fuentes.

  • CorregidoFuncionaRestaurar la paridad de los informes para personas entre las entradas audit.v2

    transmitidas y el JSON de auditoría equivalente.

    Markdown ahora comparte un único renderizador incremental, que incluye las explicaciones de comprobaciones no disponibles, los registros de exclusión y las notas finales de cobertura. XLSX comparte un mismo diseño de metadatos y escribe las incidencias y las páginas con hojas de solo escritura de tamaño acotado, conservando todas las hojas, columnas, filtros, gráficos y recuentos de origen. Las incidencias suprimidas retenidas se pueden reproducir sin materializar su colección, y las URL de ejecución que faltan usan la misma alternativa de primera página.

  • CambiadoFuncionaEtiquetar la procedencia de las auditorías PDF de forma independiente del esquema de

    auditoría compartido: rastreador nativo, exportaciones de Screaming Frog o un recopilador SF identificado explícitamente, y recopilador desconocido. Una auditoría nativa que usa el esquema de SF Analyzer ya no recibe un encabezado de Screaming Frog.

  • CambiadoFuncionaTransmitir a CSV las filas de alcance de incidencias suprimidas en lugar de acumular sus

    explicaciones renderizadas…

    Transmitir a CSV las filas de alcance de incidencias suprimidas en lugar de acumular en memoria sus explicaciones renderizadas. Las exportaciones completas de exclusiones conservan su orden y los datos de origen, mientras la asignación de memoria sigue acotada para colecciones grandes de exclusiones retenidas.

5 de octubre de 2026

1 cambiado
  • CambiadoFuncionaConciliar cada fila de brecha de cobertura a partir de su celda Mode real, validar las#830

    referencias a comprobaciones y herramientas cubiertas contra los registros públicos, y generar prioridades a partir de las filas sin resolver.

    #830 (incidencia en GitHub)

4 de octubre de 2026

56 añadido75 cambiado5 corregido
  • AñadidoFuncionaAñadir una proyección sin conexión del avance de GSC de marca y sin marca con alias#880

    Unicode explícitos…

    Añadir una proyección sin conexión del avance de GSC de marca y sin marca, con alias explícitos compatibles con Unicode, CTR ponderado compatible y bandas de posición media etiquetadas.

    #880 (incidencia en GitHub)
  • AñadidoFuncionaAñadir el agrupamiento opcional de tareas check_assignment para las asignaciones de URL#878

    de plantilla o componente declaradas…

    Añadir el agrupamiento opcional de tareas check_assignment para asignaciones de URL de plantilla o componente declaradas, o para segmentos de rastreo validados. Los elementos agrupados conservan los recuentos de ocurrencias y de URL, la evidencia limitada, la procedencia del agrupamiento, el alcance de verificación y los estados declarado, candidato, confirmado y sin asignar.

    #878 (incidencia en GitHub)
  • AñadidoFuncionaAñadir mapas de comparación de versiones url-correspondence.v1 opcionales con pares#877

    declarados de origen y URL…

    Añadir mapas opcionales de comparación de versiones url-correspondence.v1 con pares declarados de origen y URL, rechazo de colisiones, procedencia de los datos de página y salida release_review.v1.

    #877 (incidencia en GitHub)
  • AñadidoFuncionaAñadir una proyección sin conexión de cohortes de publicación con evidencia cualificada y#876

    procedencia de fechas…

    Añadir una proyección sin conexión de cohortes de publicación con evidencia cualificada, procedencia de fechas, inventario de autores, observaciones de proveedores etiquetadas y ventanas de antigüedad opcionales.

    #876 (incidencia en GitHub)
  • AñadidoFuncionaAñadir un inventario sin conexión de CTA y formularios incrustados que conserve las#875

    ocurrencias para el HTML proporcionado…

    Añadir un inventario sin conexión de CTA y formularios incrustados que conserve las ocurrencias del HTML proporcionado, con destinos ausentes anulables, salida JSON/CSV acotada y cobertura explícita de cuerpos incompletos.

    #875 (incidencia en GitHub)
  • CambiadoFuncionaConservar la clasificación de tiempo de espera remoto al ocultar los datos sensibles de#866

    los errores de transporte, y reproducir de forma segura los manifiestos de proxy directo para la verificación dirigida.

    #866 (incidencia en GitHub)
  • CambiadoFuncionaLeer la evidencia de atribución desde el grafo de enlaces SQL retenido, conservar la#866

    atribución nula explícita en la exportación…

    Leer la evidencia de atribución desde el grafo de enlaces SQL retenido, conservar la atribución nula explícita al exportar y mantener las comprobaciones de enlaces externos en cola entre reanudaciones.

    #866 (incidencia en GitHub)
  • CambiadoFuncionaRegenerar los catálogos integrados y los contratos de informes; instalar el validador PDF#866

    con el extra all y mantener las pruebas con navegador simulado independientes de la selección local de Chrome.

    #866 (incidencia en GitHub)
  • AñadidoFuncionaAñadir un plan opcional y sin conexión de carga en BigQuery que exponga tablas#837

    versionadas por esquema, requisitos de facturación y prerrequisitos explícitos de autorización, sin acceso a la nube.

    #837 (incidencia en GitHub)
  • AñadidoFuncionaAñadir un transporte REST de BigQuery con lista de permitidos y trabajos de carga#837

    deterministas en staging…

    Añadir un transporte REST de BigQuery con lista de permitidos, trabajos de carga deterministas en staging, conciliación del recuento de filas y publicación atómica documentada por tabla, en lugar de una transacción ficticia entre tablas.

    #837 (incidencia en GitHub)
  • CambiadoFuncionaExigir una aprobación cost_authorized de BigQuery separada y controlada por el host#837

    antes de cualquier token, comprobación de conjunto de datos o escritura en staging.

    #837 (incidencia en GitHub)
  • AñadidoFuncionaAñadir un generador validado y solo local de enlaces de copia para Looker Studio del#836

    paquete de informes sintético de cinco páginas…

    Añadir un generador validado y solo local de enlaces de copia para Looker Studio, destinado al paquete de informes sintético de cinco páginas; exige un ID de informe original y alias exactos de origen de Sheets o BigQuery, sin publicar ningún informe ni inventar una plantilla.

    #836 (incidencia en GitHub)
  • AñadidoFuncionaAñadir el accesorio sintético de hojas de cálculo confirmado#836

    (examples/reporting-pack/worksheets/): un CSV por cada conjunto de datos de BI, más el manifiesto, generado de forma determinista byte a byte a partir de examples/audit.json y de dos entradas sintéticas de GSC/GA4. Muestra los estados de cero medido, suprimido o ausente, solo externo, sin clave identificable, comprobación omitida, conjunto de datos no disponible y cuadrante incompleto, y se verifica como reproducible con scripts/generate_reporting_pack_worksheets.py --check.

    #836 (incidencia en GitHub)
  • AñadidoFuncionaAñadir examples/reporting-pack/SETUP.md: la guía mecánica para el propietario sobre#836

    cómo importar…

    Añadir examples/reporting-pack/SETUP.md: la guía mecánica para el propietario que explica cómo importar las seis hojas de cálculo en Google Sheets, conectar los alias reservados de origen de datos, construir las cinco páginas del esquema con los controles declarados y los campos calculados, habilitar el permiso de copia y verificar una copia nueva. La plantilla nativa de Looker Studio sigue siendo un paso externo que debe autorizar el propietario; no se incluyen ID de informe, enlaces ni escrituras en Google.

    #836 (incidencia en GitHub)
  • CambiadoFuncionaConservar los nombres de partición, los recuentos y las sumas de comprobación del paquete#836

    BI generado para que el accesorio de hoja de cálculo…

    Conservar los nombres de partición, los recuentos y las sumas de comprobación del paquete BI generado, para que el accesorio de hoja de cálculo supere la validación previa existente de Sheets y los consumidores de exportaciones filtradas. Documentar los campos de alias separados de la API de enlaces y exigir una verificación de copia nueva a través de la URL generada, sin reparar manualmente el origen.

    #836 (incidencia en GitHub)
  • CambiadoFuncionaRechazar alias duplicados de la API de enlaces tras normalizar los espacios y devolver#836

    los alias exactos usados en los parámetros de URL. Definir ID compartidos de campos de ejecución, controles de fecha de proveedor agrupados y gráficos de cobertura que excluyan poblaciones solapadas. La creación de la plantilla nativa y la verificación de copia nueva siguen siendo requisitos de aceptación externos.

    #836 (incidencia en GitHub)
  • AñadidoFuncionaAñadir filas de cohorte de URL explícitas y con evidencia cualificada a los paquetes BI#835

    locales, incluidos los cuadrantes de Search Console/GA4 seguros para el cero medido, solo para observaciones completas, compatibles y uno a uno.

    #835 (incidencia en GitHub)
  • CambiadoFuncionaCalcular las cuotas de enlaces entrantes observados a partir de páginas de enlace únicas#835

    dentro del alcance con extracción HTML completa…

    Calcular las cuotas de enlaces entrantes observados a partir de páginas de enlace únicas dentro del alcance, con extracción HTML completa, conservando por separado las ocurrencias repetidas y etiquetando las poblaciones parciales.

    #835 (incidencia en GitHub)
  • AñadidoFuncionaAñadir paquetes BI sin conexión, tipados y deterministas para rastreos y auditorías#834

    guardados y para evidencia de proveedores…

    Añadir paquetes BI sin conexión, tipados y deterministas para los rastreos y auditorías guardados y para la evidencia de proveedores aportada, con límites de particiones, estados nulos, conservación de filas y celdas CSV seguras frente a fórmulas.

    #834 (incidencia en GitHub)
  • CambiadoFuncionaConservar los hallazgos de los archivos complementarios audit.v2 acotados, unir hasta#834

    1 000 000 de URL de rastreo retenidas mediante un artefacto SQLite de evidencia duradero y volcar ese artefacto a BI sin materializar listas de páginas ni de URL coincidentes. Esto no entrega una plantilla de Looker Studio que se pueda copiar.

    #834 (incidencia en GitHub)
  • CambiadoFuncionaProyectar grupos de hallazgos, candidatos de cuadrantes de proveedores y fuentes de#834

    enlaces entrantes elegibles mediante un índice SQLite desechable y acotado. Mantener válidas las dimensiones dinámicas de proveedores en las exportaciones seleccionadas y en los planes sin conexión de Sheets y BigQuery; acotar el número de particiones y el consumo de disco.

    #834 (incidencia en GitHub)
  • CambiadoFuncionaConservar las URL de destino y los mensajes de los hallazgos de auditoría nativos como#834

    columnas BI tipadas, no solo en el JSON de origen…

    Conservar las URL de destino y los mensajes de los hallazgos de auditoría nativos como columnas BI tipadas, no solo dentro del JSON de origen conservado, de modo que las selecciones exactas de URL conserven los hallazgos afectados.

    #834 (incidencia en GitHub)
  • AñadidoFuncionaAñadir scan-fragment-links (seo_scan_fragment_links) y la comprobación de auditoría#827

    BROKEN_BOOKMARK: cada <a href> con fragmento en el HTML o DOM completo conservado se resuelve contra los ids de elemento y los destinos <a name> del documento de destino, con el algoritmo WHATWG de desplazamiento al fragmento (el fragmento serializado se prueba primero contra ids y nombres; después, el valor decodificado en porcentaje y UTF-8 se prueba contra ambos; + sigue siendo un signo más literal; # y #top se resuelven al inicio del documento). Las representaciones estática, renderizada y de fragmento heredado se evalúan de forma independiente, se respetan las reglas de redirección y de <base href>, y una cadena de consulta distinta corresponde a otro documento. Los cuerpos ausentes, truncados, no compatibles, fallidos o agotados por presupuesto se informan como omisiones con nombre —nunca como incidencias de enlace roto—, y las exportaciones de Screaming Frog y las importaciones heredadas indican que la comprobación no está disponible, en lugar de afirmar que se ejecutó sin errores. Los resultados están acotados y paginados de forma determinista (total, returned, offset/limit, next_offset, estado de cobertura), e idénticos en la CLI, en el MCP y en el resumen de auditoría del rastreo conservado. No se descarga nada: la evaluación es de solo lectura y sin conexión.

    #827 (incidencia en GitHub)
  • CambiadoFuncionaValidar los enlaces de retorno de hreflang nativos contra declaraciones completas de#825

    destinos conservados, distinguiendo un retorno ausente conocido de un destino no rastreado o con cuerpo no disponible. Informar de las alternativas noindex observadas, conservar las etiquetas sin procesar y las identidades de URL normalizadas con el contexto de duplicados y conflictos, y marcar como no medidas las relaciones de población parcial. La auditoría, la CLI, el MCP y las superficies de informes existentes transportan los mismos hallazgos sin hacer solicitudes adicionales.

    #825 (incidencia en GitHub)
  • AñadidoFuncionaAñadir CANONICAL_TARGET_ERROR para señalar las URL canonical de destino recuperadas que#824

    devuelven 4xx/5xx, con evidencia de origen, destino, respuesta e indexabilidad. Los destinos desconocidos o con estado incompleto siguen sin disponibilidad; las variantes 2xx conocidas eliminan el veredicto de error, y los destinos 3xx permanecen bajo CANONICAL_TO_REDIRECT.

    #824 (incidencia en GitHub)
  • AñadidoFuncionaAñadir CANONICAL_HOMEPAGE_GROUP para grupos de al menos tres páginas recuperadas e#824

    indexables, repartidas en dos o más secciones de ruta, con títulos y encabezados H1 distintos y con canonical apuntando a la página de inicio recuperada. Las autorreferencias y la página de inicio, las variantes con consulta, la paginación reconocible, los patrones de paginación o filtro configurados, la evidencia incompleta de la página de inicio y los rastreos nativos parciales no generan un hallazgo de todo el sitio.

    #824 (incidencia en GitHub)
  • AñadidoFuncionaAñadir evidencia objetiva de autoría, fechas y páginas de confianza a las auditorías#823

    acotadas (issue #823): ocho comprobaciones de severidad de aviso en seohead/sf/core/eeat.py que informan de lo que puede observar un rastreo, y nunca una puntuación E-E-A-T. NO_AUTHOR_BYLINE y NO_CONTENT_DATES solo se activan en páginas con forma de contenido —un tipo de artículo JSON-LD, og:type=article, un elemento <article> o una ruta de contenido convencional— y nombran los portadores que leen (meta_author, rel_author, itemprop=author, clase byline, <time datetime>, author, datePublished y dateModified de JSON-LD, una ruta de URL con forma de fecha), cada uno con una confianza declarada. MISSING_ABOUT_PAGE, MISSING_CONTACT_PAGE, MISSING_PRIVACY_POLICY y MISSING_TERMS_PAGE informan uno de found_indexable (silencioso), found_non_indexable, found_error, discovered_not_crawled o not_discovered, de modo que una página que existe pero no responde nunca se lea igual que una que nadie enlazó. FEW_CITATIONS informa solo de lo que pueden demostrar las posiciones de los enlaces —un enlace saliente dentro del texto del cuerpo o un recuento declarado de cero—, y YMYL_REVIEW_CANDIDATE marca coincidencias deterministas de palabra completa en la ruta o el título para revisión humana, nunca una clasificación. Lo no medido se mantiene distinto de lo ausente en todo momento: una página cuyo cuerpo nunca se analizó conserva trust_signals en NULL y se cuenta en el motivo de omisión, y summary.trust_evidence registra el alcance evaluado, el estado por tipo y por página, y una advertencia de rastreo parcial para los veredictos not_discovered.

    #823 (incidencia en GitHub)
  • CambiadoFuncionaClasificar el p75 de LCP, INP y CLS de campo de la ventana actual de CrUX frente a#822

    umbrales oficiales versionados, conservando el alcance de URL u origen, factor de forma y periodo de recopilación. Los datos de campo ausentes, incompletos o fallidos siguen como no disponibles o parciales.

    #822 (incidencia en GitHub)
  • AñadidoFuncionaAñadir muestreo explícito y acotado de URL con caché privada opcional, y aceptar#822

    evidencia guardada de CrUX en las auditorías de sitio y en los informes sin solicitudes automáticas al proveedor. Acotar los bytes de respuesta y de caché, y rechazar recuentos de muestra guardados incoherentes o registros de URL repetidos, en lugar de informar una cobertura de campo completa.

    #822 (incidencia en GitHub)
  • CambiadoFuncionaDocumentar el límite actual de la CLI de Docker de un solo uso por separado del servicio#820

    opcional de API remota y trabajador…

    Documentar el límite actual de la CLI de Docker de un solo uso por separado del servicio opcional de API remota y de trabajador, construido de forma explícita.

    #820 (incidencia en GitHub)
  • AñadidoFuncionaAñadir la receta de ejecución SSH con espacio de trabajo persistente y explicar que el#820

    estado de salida y de artefactos de la CLI…

    Añadir la receta de ejecución SSH con espacio de trabajo persistente y explicar que el código de salida y el estado de los artefactos de la CLI no son una comprobación de salud de un servicio HTTP.

    #820 (incidencia en GitHub)
  • CambiadoFuncionaAdmitir configuraciones explícitas de rastreo SQLite nativo de hasta 1 000 000 de URL con#818

    un presupuesto separado…

    Admitir configuraciones explícitas de rastreo SQLite nativo de hasta 1 000 000 de URL, con un presupuesto separado de 2 000 000 de solicitudes HTTP y el perfil sintético existente de solo almacenamiento. La CLI, el MCP, la cola remota y los trabajadores respetan los mismos presupuestos declarados. Las API materializadas heredadas y de listas conservan un límite de seguridad explícito de 50 000 URL; las comprobaciones de robots, los reintentos y los saltos de redirección y canonical de las listas ahora comparten su presupuesto de solicitudes. Las auditorías nativas y el reanálisis sin conexión usan la ruta acotada audit.v2 sin la antigua negativa del puente, que superaba 10 000 páginas o 20 000 formularios. Los contadores del escritor transaccional evitan volver a recorrer la cola de URL pendientes en cada lote. Un controlador manual de aceptación registra las identidades de origen cargadas, la interrupción y reanudación, y los consumidores posteriores; la admisión, por sí sola, no es evidencia de una aceptación completada de un millón de URL.

    #818 (incidencia en GitHub)
  • CambiadoFuncionaEjecutar cada etapa manual de aceptación nativa bajo un vigilante de recursos de#818

    subproceso, conservar los artefactos interrumpidos, verificar cada fila CSV o XLSX y la cobertura de tareas, y probar por separado el HTTP protegido en loopback propio, con el ritmo predeterminado sin cambios.

    #818 (incidencia en GitHub)
  • CambiadoFuncionaPermitir duraciones de rastreo remoto explícitamente autorizadas de hasta 14 días,#818

    conservando la hora predeterminada…

    Permitir duraciones de rastreo remoto explícitamente autorizadas de hasta 14 días, conservando el valor predeterminado de una hora y los presupuestos independientes de proyecto, solicitudes, disco, concesión y renderizado. Esto permite que un objetivo de un millón de páginas quepa en su tasa de solicitudes respetuosa sin cambios; los valores por encima del techo de duración y los tipos no válidos fallan antes de la recopilación.

    #818 (incidencia en GitHub)
  • CambiadoFuncionaEl reanálisis sin conexión usa un plazo nuevo para cada operación de ejecución o#818

    recuperación de SQLite, conservando la interrupción y la cancelación de consultas, sin cargar contra el plazo de validación de apertura del rastreo original el tiempo de análisis en Python ni las escrituras derivadas.

    #818 (incidencia en GitHub)
  • CambiadoFuncionaLa opción crawl-site --out-dir heredada conserva ahora la evidencia de páginas, enlaces#817

    y formularios en archivos JSONL complementarios…

    La opción heredada crawl-site --out-dir conserva ahora la evidencia de páginas, enlaces y formularios en archivos JSONL complementarios de solo anexión durante la recopilación y la reanudación, en lugar de retener listas duplicadas en memoria. Los puntos de control verifican los recuentos de los complementarios; los puntos de control v4 antiguos con formularios en línea migran sin perder hallazgos de formularios. El puente de auditoría existente nombra sus límites de materialización de páginas, formularios y enlaces, y conserva la evidencia recopilada cuando la auditoría no está disponible. Un informe anterior se conserva con un nombre de archivo obsoleto en lugar de presentarse como la ejecución actual. La escalada nativa de JavaScript lee los registros de página a través de una vista SQLite reiterable, en lugar de reconstruir todos los objetos de página. La transmisión completa de auditorías grandes sigue en seguimiento en #816/#817.

    #817 (incidencia en GitHub)
  • CambiadoFuncionaAlmacenar auditorías nativas de gran tamaño en archivos complementarios audit.v2#817

    ordenados en lugar de descartar la disponibilidad…

    Almacenar auditorías nativas de gran tamaño en archivos complementarios audit.v2 ordenados, en lugar de descartar la disponibilidad de la auditoría.

    #817 (incidencia en GitHub)
  • CambiadoFuncionaTransmitir la normalización de auditoría nativa a su contexto sin una lista intermedia de#817

    registros.

    #817 (incidencia en GitHub)
  • CorregidoFuncionaMantener los mapas de páginas de auditoría nativa y las métricas derivadas por página en#817

    un almacén de contexto SQLite temporal.

    #817 (incidencia en GitHub)
  • CorregidoFuncionaMantener los hallazgos nativos en disco hasta que la agregación ordenada asigne sus#817

    identidades de informe.

    #817 (incidencia en GitHub)
  • CorregidoFuncionaMantener los grupos nativos de duplicados y contenido en almacenamiento SQLite ordenado#817

    durante el análisis.

    #817 (incidencia en GitHub)
  • CambiadoFuncionaAcotar las búsquedas repetidas de páginas, agrupar los backlinks de hallazgos y resolver#817

    las profundidades de descubrimiento nativo sin reconstruir cada ruta ni cargar cada nodo en Python. Las rutas largas conservan su profundidad exacta y los extremos truncados quedan explícitos.

    #817 (incidencia en GitHub)
  • CambiadoFuncionaTransmitir la entrada de página nativa conservada y las búsquedas de enlaces entrantes#817

    antes de construir el contexto.

    Derivar las relaciones del corpus no vacío y de hreflang mediante índices respaldados en disco, conservar las colecciones completas de evidencia en audit.v2 y etiquetar las muestras acotadas de hallazgos de relación con sus recuentos exactos de ocurrencias.

    #817 (incidencia en GitHub)
  • CambiadoFuncionaAcotar la caché de páginas por los bytes decodificados estimados de Python, además del#817

    número de entradas; las páginas sin caché…

    Acotar la caché de páginas por los bytes decodificados estimados de Python, además del número de entradas; las páginas grandes sin caché siguen siendo legibles y las mutaciones invalidan su peso anterior en caché. Conservar los rangos de tamaño HTML como pares escalares estables de URL y tamaño, en lugar de retener cada modelo completo de página, y evitar retener el JSON serializado de página en los callbacks de mutación.

    #817 (incidencia en GitHub)
  • CambiadoFuncionaConservar solo los datos escalares de URL, estado, indexabilidad, canonical y redirección#817

    mientras se comprueban los pares con barra final…

    Conservar solo los datos escalares de URL, estado, indexabilidad, canonical y redirección mientras se comprueban los pares con y sin barra final, y cerrar explícitamente las conexiones SQLite duraderas del adaptador y de los trabajos remotos.

    #817 (incidencia en GitHub)
  • CambiadoFuncionaTransmitir los recuentos de cobertura de cuerpos no disponibles y de charset, conservar#817

    el estado escalar de selección de páginas de confianza en lugar de las poblaciones de páginas candidatas, y procesar las coincidencias de DOM en HTML almacenado en dos pasadas sobre el índice de archivos fijo. Conservar el orden del representante de las variantes normalizadas, los ejemplos de URL existentes, la cobertura completa de fuentes coincidentes y cada hallazgo.

    #817 (incidencia en GitHub)
  • CambiadoFuncionaValidar fila a fila el JSONL de puntos de control de rastreo heredado antes de añadirlo,#817

    rechazando evidencia ausente, corrupta o sin terminar, sin reemplazarla. Comparar los puntos de control de formularios en línea más antiguos con su complementario sin asignar una segunda lista de formularios.

    #817 (incidencia en GitHub)
  • AñadidoFuncionaAñadir la continuación de la prueba comparativa de JavaScript con procedencia verificada#817

    entre pares completados, conservando los recibos anteriores y los presupuestos de disco. Los casos interrumpidos siguen como bloqueos explícitos. Exigir una consulta o un reanálisis exitosos y evidencia CSV completa de páginas antes de marcar un caso de prueba comparativa como superado.

    #817 (incidencia en GitHub)
  • CambiadoFuncionaConservar listas explícitas de URL con el escritor SQLite nativo, preservando el orden#817

    exacto de entrada, varios hosts y la semántica de no descubrimiento. Transmitir la entrada de archivos de intercambio, conservar los presupuestos de solicitudes y de tiempo durante la reanudación de la recopilación, retener la evidencia acotada de respuestas y saltos, y mantener las comprobaciones de grafo y de formularios explícitamente no disponibles. Las listas de directorios grandes usan el mismo almacenamiento temporal con un puente de auditoría JSON acotado por separado.

    #817 (incidencia en GitHub)
  • AñadidoFuncionaAñadir un archivo complementario SQLite audit.v2 versionado para colecciones de auditoría#816

    completas y ordenadas que superen el límite de tamaño de JSON en línea, con vinculación de procedencia del rastreo y validación de integridad de extremo a extremo.

    #816 (incidencia en GitHub)
  • CambiadoFuncionaTransmitir informes audit.v2 en JSON, CSV, XLSX, Markdown y DOCX, comparar poblaciones de#816

    hallazgos de severidad alta…

    Transmitir informes audit.v2 en JSON, CSV, XLSX, Markdown y DOCX, comparar las poblaciones de hallazgos de severidad alta y mantener las operaciones de instantánea y poda emparejadas con el complementario, conservando el esquema scan.v1.

    #816 (incidencia en GitHub)
  • CambiadoFuncionaConservar una sola vez la pertenencia a grupos ordenados grandes en la revisión 3 del#816

    almacenamiento audit.v2 y la revisión 5 del registro…

    Conservar una sola vez la pertenencia a grupos ordenados grandes en la revisión 3 del almacenamiento audit.v2 y en la revisión 5 del registro, con lecturas de auditoría retrocompatibles, migración atómica del registro, paginación explícita de miembros mediante CLI o MCP, y complementarios de pertenencia BI completos y vinculados a su fuente.

    #816 (incidencia en GitHub)
  • CambiadoFuncionaConservar el digest de origen audit.v2 durante el reanálisis sin conexión; persistir el#816

    alcance incompleto de grupos del registro…

    Conservar el digest de origen audit.v2 durante el reanálisis sin conexión; persistir el alcance incompleto de los grupos del registro y cerrar los recursos de ingesta tras una validación fallida.

    #816 (incidencia en GitHub)
  • CambiadoFuncionaReutilizar el resumen exacto de capacidades del corpus mientras un rastreo nativo solo de#815

    metadatos no tiene evidencia de respuesta, documento, cuerpo ni recurso, evitando relecturas de todo el corpus en cada confirmación de página dispersa, sin cambiar el almacenamiento del rastreo.

    #815 (incidencia en GitHub)
  • AñadidoFuncionaAñade un perfilador de capacidad de escaneo nativo, opcional y sin conexión, con enlaces#815

    y DOM…

    Añade un perfilador de capacidad de escaneo nativo, opcional y sin conexión, con enlaces, HTML conservado y DOM renderizado dimensionados por separado, presupuestos de recursos explícitos y un ejercicio de pérdida de proceso y reanudación. Informa del límite de admisión existente de 50 000 URL y de la finalización incompleta como evidencia bloqueada, no como capacidad.

    #815 (incidencia en GitHub)
  • CambiadoFuncionaNombra la cancelación de solicitudes fijadas del navegador como render_cancelled y#811

    cierra el contexto aislado…

    Nombra la cancelación de solicitudes fijadas del navegador como render_cancelled y cierra el contexto remoto aislado y el navegador al cancelar o al desconectarse, sin recurrir a una alternativa local.

    #811 (incidencia en GitHub)
  • CambiadoFuncionaPermite que la configuración remota de proyecto de confianza aporte referencias de#810

    credenciales de entorno vinculadas al host, con procedencia conservada y redactada, y falla antes de recopilar datos si una referencia no está disponible.

    #810 (incidencia en GitHub)
  • CambiadoFuncionaPermite un transporte remoto de Playwright gestionado por el servicio y con control de#809

    versión para un proyecto en cola, manteniendo su endpoint fuera de los envíos y conservando las solicitudes de navegador fijadas y sujetas a política.

    #809 (incidencia en GitHub)
  • AñadidoFuncionaExpone las rutas observadas, los enlaces entrantes inversos y el contexto de aparición de#807

    un escaneo guardado mediante una única consulta compartida de CLI y MCP, acotada y de solo lectura, con identidad de escaneo explícita y resultados de error.

    #807 (incidencia en GitHub)
  • AñadidoFuncionaAñade la ubicación de enlaces por aparición y el contexto del encabezado más cercano,#806

    acotados y de solo lectura, a partir del HTML estático conservado y del DOM renderizado. Preserva los ID de enlace duplicados y los estados explícitos de evidencia no disponible o parcial.

    #806 (incidencia en GitHub)
  • AñadidoFuncionaNuevo comando semantic-inputs (seo_semantic_inputs por MCP) que construye el#801

    manifiesto de entradas…

    Nuevo comando semantic-inputs (seo_semantic_inputs por MCP) que construye el manifiesto reproducible de entradas normalizadas que consumirá el trabajo de similitud semántica. Por cada documento registra el hash del cuerpo conservado, el hash exacto de la entrada decodificada, el hash de la salida normalizada, la estrategia de área de contenido y la evidencia de idioma (el propio <html lang> de la página y la proporción de letras por sistema de escritura), pero nunca el texto normalizado en sí. --scan lee en flujo los cuerpos completos conservados, sin conexión y con la configuración de área de contenido registrada en el rastreo, sin volver a descargar nada. Un cuerpo ausente o parcial queda como omisión explícita y nunca como un resultado limpio y vacío (#801).

    #801 (incidencia en GitHub)
  • CambiadoFuncionaValida páginas, tamaño, texto extraíble y conservación del modelo de origen del PDF de#800

    auditoría técnica…

    Valida el número de páginas, el tamaño en bytes, el texto extraíble y la conservación de los registros del modelo de origen del PDF de auditoría técnica antes de publicar un informe renderizado.

    #800 (incidencia en GitHub)
  • AñadidoFuncionaAñade salida PDF bilingüe de Chromium sin conexión a las rutas compartidas de#799

    report-build de CLI y MCP, validando y saneando el archivo temporal antes de reemplazarlo de forma atómica.

    #799 (incidencia en GitHub)
  • AñadidoFuncionaAñade diseños PDF de auditoría técnica autocontenidos en inglés y ruso, con tokens de#798

    marca neutros, gráficos de gravedad y cobertura, estados explícitos de ejecución incompleta y flujo de páginas para contenido extenso.

    #798 (incidencia en GitHub)
  • CorregidoFuncionaMantiene el diseño del PDF separado de la construcción del modelo de auditoría y de la#798

    integración con CLI y MCP.

    #798 (incidencia en GitHub)
  • AñadidoFuncionaAñade un modelo de contenido PDF de auditoría técnica, versionado y sin conexión, que#797

    conserva los registros de origen, los recuentos exactos de origen y proyectados, el alcance y los estados de cobertura de ambos contratos de auditoría compatibles.

    #797 (incidencia en GitHub)
  • CambiadoFuncionaPersiste versiones de escenarios de flujo, contexto de sitio y competencia, evidencia por#796

    paso y puertas de revisión…

    Persiste las versiones registradas de los escenarios de flujo, el contexto del sitio y de la competencia, la evidencia por paso y las puertas de revisión. Una sesión local posterior solo puede reanudar las ejecuciones interrumpidas si sus dependencias actuales siguen siendo válidas.

    #796 (incidencia en GitHub)
  • CambiadoFuncionaExige una lista de trabajo del controlador para iniciar flujos y conserva acuses de#796

    triaje de notas de especialista…

    Exige una lista de trabajo del controlador para iniciar flujos y conserva acuses explícitos de triaje de notas de especialista para los resultados de tarea, objetivo, competidor, bloqueado o rechazado.

    #796 (incidencia en GitHub)
  • CambiadoFuncionaExige que los puntos de control de flujo verifiquen los bytes de los artefactos#796

    conservados frente a sus recibos SHA-256…

    Exige que los puntos de control de flujo exitosos verifiquen los bytes de los artefactos conservados y vinculados al proyecto frente a sus recibos SHA-256. Si la evidencia falta o ha cambiado, la finalización anterior queda obsoleta sin reescribir el historial; los presupuestos de verificación nunca certifican evidencia en silencio ni descartan su recibo.

    #796 (incidencia en GitHub)
  • CambiadoFuncionaPermite perfiles explícitos y acotados de política de hash de evidencia, normalizando las#796

    políticas antiguas.

    La observación pasiva de flujos comprueba los metadatos de verificación conservados sin volver a calcular el hash de los artefactos; los recibos modificados o no verificados quedan explícitos.

    #796 (incidencia en GitHub)
  • AñadidoFuncionaAñade el comando CLI project progress acotado y paginado y la herramienta MCP#795

    seo_project_progress, con recuentos por estado de la lista de comprobación y los siguientes elementos accionables. La vista reutiliza los resultados de cobertura con alcance y solo muestra un porcentaje de finalización de tareas de auditoría, claramente etiquetado, cuando cada sitio incluido tiene un plan acordado y un denominador de tareas medido y no vacío. La cobertura de la población de URL se mantiene por separado.

    #795 (incidencia en GitHub)
  • CambiadoFuncionaLas listas de comprobación de proyecto ya pueden registrar el alcance de auditoría#794

    acordado e informar de cobertura honesta…

    Las listas de comprobación de proyecto ya pueden registrar el alcance de auditoría acordado e informar de proporciones de cobertura honestas (#794). project-checklist-init y seo_project_checklist_init aceptan un plan opcional: un revisor, una population de URL declarada como complete_set, una sample con nombre o unknown, con su source, size o urls enumeradas y, si se quiere, poblaciones por templates, además de un acuerdo opcional de tasks (all_agreed, o una selection con IDs de elementos de la lista ya existentes). Todo queda vinculado a la identidad del sitio del proyecto y marcado con la revisión de escritura. Registrar un plan actualiza la lista a seohead.coverage.v3 y añade el plan al historial conservado. Volver a registrar un acuerdo idéntico es una operación idempotente sin efecto. Si el acuerdo cambia, la evidencia anterior queda marcada como obsoleta en lugar de reevaluarse con un denominador distinto. Los documentos v3 de plan único se migran al leerlos. Leer, reconciliar o aplicar prioridades nunca actualiza ni inventa una población, y los documentos v1 y v2 siguen cargándose sin cambios. Los elementos fuera de una selección se informan como not_agreed, visibles fuera de todos los denominadores.

    #794 (incidencia en GitHub)
  • CambiadoFuncionaLa finalización de la lista sigue el alcance medido: un elemento automático de sitio con#794

    medición parcial…

    La finalización de la lista de comprobación ahora sigue el alcance medido. Un elemento automático de ámbito sitio respaldado por una medición limitada (escaneo parcial) sigue sin terminar en lugar de contar como completado, mientras que un elemento acotado a URL de muestra explícitas sí se da por terminado cuando el artefacto cubre exactamente ese alcance. El indicador complete de nivel superior ahora significa que la auditoría con alcance está terminada: todas las tareas acordadas aplicables están hechas, no hay exclusiones pendientes y la población de URL acordada está cubierta por completo por mediciones verificadas. Así, un alcance desconocido o no medido nunca puede dar por completada una auditoría.

    #794 (incidencia en GitHub)
  • CambiadoFuncionaEl estado de la lista devuelve coverage con cinco proporciones separadas:#794

    audit_tasks, checks…

    El estado de la lista de comprobación devuelve coverage con cinco proporciones separadas: audit_tasks, checks (con measured_urls), manual_review, deliverable_review y url_population. Cada una tiene su propio basis, numerator, denominator y state, de modo que un recuento de URL nunca se mezcla con un recuento de comprobaciones o de tareas. Un denominador que no puede justificarse se queda en null con state: "unknown" y un motivo, en lugar de convertirse en 0/0 o en 100 %. Las mediciones que no pueden verificarse frente a la población acordada mantienen el eje de URL en partial y solo cuentan las URL elegibles verificadas. La pertenencia a URL se verifica con la enumeración acordada, así que una población declarada solo por size no cuenta ninguna URL medida, y el numerador nunca puede superar su denominador. Las poblaciones por plantilla se validan como subpoblaciones acordadas de la población del sitio al registrar o leer un plan: las URL enumeradas de una plantilla deben pertenecer al conjunto enumerado del sitio, y la pertenencia declarada a una plantilla nunca puede superar el tamaño acordado del sitio. Un plan incoherente se rechaza, no se recorta ni se cuenta por encima del denominador. La evidencia de comprobación guardada incluye ahora la enumeración de URL medida, de modo que el numerador de URL es un conjunto auditable y no un recuento de filas. La agregación multisitio suma los ejes por sitio y pasa a unknown siempre que un sitio no pueda justificar su denominador.

    #794 (incidencia en GitHub)
  • CambiadoFuncionaUn registro not_applicable es ahora una exclusión revisada: exige un motivo, un revisor#794

    y una base de evidencia inspeccionable, es decir, un artifact con hash y relativo al proyecto, o una referencia evidence explícita. Las exclusiones revisadas conservan su ID estable y su historial, salen de los denominadores de tarea solo mediante esa decisión registrada y se listan por separado en exclusions. Un elemento desactivado, un registro de exclusión obsoleto o un registro not_applicable heredado, escrito antes de la regla de base de evidencia, permanece en el denominador como pending_exclusion hasta que se revise de nuevo. Así, desactivar, retirar del catálogo o reclasificar nunca reduce en silencio los recuentos acordados. Una exclusión revisada nueva sobre un elemento retirado del catálogo se resuelve con normalidad, en lugar de quedarse pendiente para siempre.

    #794 (incidencia en GitHub)
  • AñadidoFuncionaAñade el prompt direccionable workflow/full-audit-v1 y el escenario full-audit por#793

    las rutas de catálogo…

    Añade el prompt direccionable workflow/full-audit-v1 y el escenario full-audit a través de las rutas existentes del catálogo de skills y escenarios de CLI y MCP. El flujo reutiliza las rutas de recopilación y de método ya incluidas, condiciona la verificación y el informe a la evidencia real y separa la preparación del proyecto de la finalización de la auditoría completa.

    #793 (incidencia en GitHub)
  • CambiadoFuncionaVincula las decisiones de corrección a artefactos de verificación inmutables y a hashes#792

    exactos de evidencia antes y después…

    Vincula las decisiones de corrección a artefactos de verificación inmutables y a los hashes exactos de evidencia de antes y de después, incluidas las líneas base de audit.v2 procesadas en flujo.

    #792 (incidencia en GitHub)
  • CambiadoFuncionaInforma de los resultados de corrección conservados con estados de cobertura representada#791

    y de alcance completo, denominadores por tarea y páginas de casos acotadas para registros de gran tamaño.

    #791 (incidencia en GitHub)
  • AñadidoFuncionaAñade reverificaciones de corrección acotadas por registro que reutilizan el verificador#790

    protegido, procesan en flujo las selecciones de audit.v2 y rechazan cualquier desvío de alcance.

    #790 (incidencia en GitHub)
  • CambiadoFuncionaVincula la verificación de correcciones a la identidad de auditoría conservada y a la#790

    política original que afecta a los resultados. Un UUID de escaneo reutilizado por sí solo ya no puede resolver un caso anterior.

    #790 (incidencia en GitHub)
  • AñadidoFuncionaAñade el registro de correcciones ledger.v1 (seohead.storage.ledger, identificador de#788

    aplicación SEOL): un artefacto SQLite separado y vinculado al proyecto que registra hallazgos, la identidad de cada aparición, la pertenencia de URL afectadas y el historial de observaciones de solo adición, a partir de auditorías scan.v1 y scan.v2 validadas, sin modificar los escaneos de origen. La ingesta vincula cada origen por UUID de escaneo, revisión de evidencia, hash de auditoría e identidad de productor y configuración. Las réplicas exactas son idempotentes y los bytes en conflicto bajo la misma revisión se rechazan de forma atómica. La cobertura capped y aggregate_only, y la evidencia unavailable, se conservan como datos y no se tratan en silencio como resueltas. Incluye migración transaccional 0→1, validación completa del esquema y de la integridad al abrir, y docs/LEDGER.md (#788).

    #788 (incidencia en GitHub)
  • AñadidoFuncionaAñade un perfil desechable de proxy inverso TLS en loopback que verifica el aislamiento#787

    autenticado de artefactos, la copia de seguridad y la restauración, la caducidad y la reversión atómica de actualizaciones, sin desplegar ningún servicio.

    #787 (incidencia en GitHub)
  • CambiadoFuncionaDocumenta los trabajos CLI de SSH de una sola ejecución, los registros de artefactos e#787

    incidentes y la recuperación sintética…

    Documenta los trabajos CLI de SSH de una sola ejecución, los registros de artefactos e incidentes, la recuperación sintética y el límite separado y futuro para la salud del servicio, el proxy, TLS y el cortafuegos.

    #787 (incidencia en GitHub)
  • AñadidoFuncionaAñade el perfil de operador de servicio remoto autoalojado para vinculaciones privadas y#787

    salud autenticada…

    Añade el perfil de operador de servicio remoto autoalojado para vinculaciones privadas, evidencia de salud autenticada, referencias a archivos de secretos, registros de incidentes, restauración con consistencia SQLite, reversión de versiones y caducidad explícita de los artefactos terminales.

    #787 (incidencia en GitHub)
  • AñadidoFuncionaAñade una política de destino remoto vinculada al proyecto para trabajos futuros en cola.#786

    Cuando un worker la vincula, valida los destinos y la configuración, vuelve a comprobar el DNS en el momento del envío, fija las solicitudes HTTP y de recursos del navegador, y aplica presupuestos de solicitudes por origen y totales. Los proxies remotos y los backends de navegador alternativos fallan en modo seguro hasta que se demuestre que su salida es segura.

    #786 (incidencia en GitHub)
  • AñadidoFuncionaAñade una cola SQLite aislada por proyecto y un worker de escaneo nativo con lease para#785

    la API remota opcional…

    Añade una cola SQLite aislada por proyecto y un worker de escaneo nativo con lease para la API remota autenticada opcional. Los trabajos conservan los escaneos nativos y los informes JSON y Markdown, admiten envío idempotente, cancelación, recuperación tras fallos al reiniciar, descargas de artefactos con alcance y retención explícita, sin activar ningún listener por defecto.

    #785 (incidencia en GitHub)
  • CambiadoFuncionaDefine un contrato opcional, autenticado y versionado de API remota de escaneo, con#784

    ajustes de rastreo acotados…

    Define un contrato opcional, autenticado y versionado de API remota de escaneo, con ajustes de rastreo nativos y acotados, permisos por proyecto, envío idempotente, esquema OpenAPI y evidencia compatible con el estado del escaneo. Requiere workers duraderos separados y una política de destinos y de salida. Las instalaciones locales de CLI y MCP no cambian (#784).

    #784 (incidencia en GitHub)
  • AñadidoFuncionaAñade un runbook SSH de Ubuntu con versión fijada y una prueba de humo del ciclo de vida#783

    en Linux desechable que demuestra la instalación, el renderizado de JavaScript, el descubrimiento de artefactos, la actualización, la evidencia de versión y la reversión, sin servicio remoto.

    #783 (incidencia en GitHub)
  • CambiadoFuncionaNormaliza la evidencia importada de analítica y búsqueda para cruces con escaneos (#781).#781

    evidence-normalize lee una exportación CSV, XLSX o JSON suministrada, o un sobre seohead.provider-evidence.v1 guardado, totalmente sin conexión, y genera un documento versionado seohead.normalized-evidence.v1 según un manifiesto opcional seohead.evidence-mapping.v1. Conserva la procedencia de cada campo (del sobre, declarada o desconocida) para la fuente, la identidad del informe, el periodo, la zona horaria, la atribución, el motor, la cobertura de recopilación y el vínculo con URL. Un valor medido 0 sigue siendo cero. Las filas ausentes, las celdas nulas o en blanco, las celdas con fórmula, los valores suprimidos, los periodos no recopilados y la recopilación fallida u omitida siguen como no disponibles de forma explícita. evidence-join une la evidencia normalizada con una lista de escaneo, auditoría o páginas según la política estricta de claves external_join.v1, con relajaciones explícitas únicamente. Conserva las poblaciones coincidentes, solo rastreadas, solo externas y no vinculables en su granularidad declarada, e informa de las colisiones de claves en lugar de multiplicar filas. --compare junto con una política declarada añade una decisión pura de compatible, incompatible o desconocido según el periodo, el límite de zona horaria, la identidad, la atribución, el motor y la granularidad. Además, informa de la elegibilidad de cuadrantes con cero medido para el trabajo posterior de cohortes. Las fuentes restringidas mantienen filas e identificadores dentro de un artefacto local privado y devuelven solo recuentos.

    #781 (incidencia en GitHub)
  • AñadidoFuncionaAñade una experiencia de preparación de proveedores sin conexión con referencias de#780

    credenciales redactadas…

    Añade una experiencia de preparación de proveedores sin conexión, con referencias de credenciales redactadas, esquemas de rutas de operación, metadatos de cuota y privacidad, y estados explícitos de acceso al destino. La mera presencia de una credencial nunca verifica el permiso.

    #780 (incidencia en GitHub)
  • CambiadoFuncionaAmplía seohead watch hasta convertirlo en un observador de proyecto de solo lectura con#775

    navegación por hallazgos…

    Amplía seohead watch hasta convertirlo en un observador de proyecto de solo lectura, con navegación por hallazgos conservados, detalle de evidencia, estado de vistas guardadas y de revisión, y avisos de bandeja de MCP con alcance explícito.

    #775 (incidencia en GitHub)
  • AñadidoFuncionaAñade entrega autorizada de informes sintéticos con recibos de idempotencia persistentes#773

    y reinicio seguro…

    Añade entrega autorizada de informes sintéticos con recibos de idempotencia persistentes y un comportamiento de reinicio seguro ante reintentos.

    #773 (incidencia en GitHub)
  • CambiadoFuncionaConserva las reclamaciones de entrega inciertas tras una salida del proceso o una#773

    confirmación de documento malformada, evitando una segunda subida automática cuando no pueda establecerse la aceptación.

    #773 (incidencia en GitHub)
  • CambiadoFuncionaMide las vistas previas de informes a partir de la evidencia conservada, con tamaño#772

    renderizado y hash de origen…

    Mide las vistas previas de informes a partir de la evidencia conservada, incluidos el tamaño renderizado, el hash de origen, los recuentos de población, la cobertura y el perfil. Informa de los renderizadores ausentes y de las entradas demasiado grandes antes de enviar. Ajusta el presupuesto de JS del asistente completo al contrato de cola compartido.

    #772 (incidencia en GitHub)
  • CambiadoFuncionaConserva las identidades exactas de envío del bot confirmadas tras caídas de cola o de#771

    propiedad…

    Conserva las identidades exactas de envío del bot confirmadas tras caídas de la cola o de la propiedad, deduplica las actualizaciones de confianza y aísla el estado, la cancelación, la recuperación y la entrega por actor o chat que inicia cada trabajo. Las repeticiones intencionales e idénticas siguen siendo trabajos separados.

    #771 (incidencia en GitHub)
  • CorregidoFuncionaRestaura el último trabajo confirmado de actor y chat tras reiniciar el servicio,#771

    conservando la cancelación…

    Restaura el último trabajo confirmado de actor y chat tras reiniciar el servicio, conservando el comportamiento de cancelación y de reejecución tras una nueva confirmación, sin reanudar un borrador no confirmado.

    #771 (incidencia en GitHub)
  • AñadidoFuncionaAñade el paquete de evidencias de revisión de software para autoalojamiento, revisión#761

    legal y compras (#761). scripts/generate_review_pack.py genera y verifica un inventario versionado de dependencias y licencias, con un perfil por grupo de instalación, versiones resueltas y fuentes de licencia medidas en el entorno de generación. Los requisitos excluidos por marcador, no satisfechos por la especificación o no instalados se registran en lugar de descartarse. Además genera un documento de procedencia a nivel de versión que vincula las distribuciones compiladas con una etiqueta y con la revisión de origen del manifiesto de compilación incrustado, y un SHA256SUMS.txt que cubre todo lo anterior. La generación rechaza una etiqueta que no coincida con pyproject.toml. La verificación vuelve a comprobar formatos y hashes registrados, reextrae cada distribución para revalidar su manifiesto incrustado, el nombre y la versión que declara su nombre de archivo, y los campos Name y Version de su propio *.dist-info/METADATA o PKG-INFO frente a pyproject.toml, sin confiar en el registro. Un escaneo de centinelas SEOHEAD_REVIEW_CANARY_* demuestra que los archivos del paquete y los diagnósticos no contienen credenciales ni marcas de cliente sembradas. La CI regenera y verifica el paquete con una etiqueta desechable en cada ejecución. El flujo de publicación lo verifica y lo adjunta a una versión v* real.

    #761 (incidencia en GitHub)
  • AñadidoFuncionaAñade docs/SOFTWARE_REVIEW.md: el mapa de endpoints salientes y de flujos de datos (a#761

    qué llama cada función, qué envía y si la llamada es opcional), el límite entre local y remoto, el almacenamiento de credenciales y artefactos, el estado de la telemetría, la notificación de seguridad y el estado de mantenimiento, y cómo revisar los cambios de cada versión. Enlaza los runbooks de instalación y despliegue en lugar de duplicarlos (#783, #787).

    #761 (incidencia en GitHub)
  • AñadidoFuncionaAñade una comprobación previa sin conexión de capacidad y sumas de control para Google#760

    Sheets…

    Añade una comprobación previa sin conexión de capacidad y de sumas de control para Google Sheets, destinada a paquetes BI locales completos. No hace ninguna solicitud a Google ni escribe en ninguna hoja de cálculo.

    #760 (incidencia en GitHub)
  • AñadidoFuncionaAñade un transporte explícito de reemplazo para Google Sheets con lista de permitidos y#760

    asignaciones por conjunto de datos…

    Añade un transporte explícito de reemplazo para Google Sheets con lista de permitidos, asignaciones de hoja por conjunto de datos, preparación y relectura acotadas, y una única publicación atómica solo de valores que conserva los ID de hoja existentes.

    #760 (incidencia en GitHub)
  • CambiadoFuncionaRegistra la preparación de Google Sheets en un punto de control antes de crear hojas#760

    remotas…

    Registra la preparación de Google Sheets en un punto de control antes de crear cualquier hoja de preparación remota, y concilia una respuesta de inicio perdida mediante sus identidades deterministas de hoja de preparación antes de reintentar.

    #760 (incidencia en GitHub)
  • CambiadoFuncionaConserva valores tipados y relecturas dispersas de Google, rechaza hojas de destino#760

    duplicadas…

    Conserva los valores numéricos y booleanos tipados y las relecturas dispersas de Google, rechaza destinos de hoja duplicados y la deriva del contrato de conjuntos de datos, vincula la recuperación al destino exacto configurado y conserva la preparación reanudable tras agotar la cuota. Presupuesta el crecimiento de la cuadrícula de destino antes del reemplazo atómico e informa de los recuentos de filas no confirmados en las ejecuciones interrumpidas.

    #760 (incidencia en GitHub)
  • CambiadoFuncionaValida complementos de grupo completos y vinculados al origen antes de escribir en#760

    destino…

    Valida los complementos de grupo completos y vinculados al origen antes de escribir en el destino, los conserva junto con los hallazgos seleccionados e informa en los recibos de destino y del libro de cálculo de que las referencias de pertenencia son solo locales, sin afirmar que el complemento se haya subido.

    #760 (incidencia en GitHub)
  • CambiadoFuncionaDivide los conjuntos grandes de registros de scan-export en XLSX en hojas numeradas y#759

    una hoja Partitions…

    Divide los conjuntos grandes de registros de scan-export en XLSX en hojas numeradas y deterministas, con una hoja Partitions que conserva el número de filas, en lugar de fallar al llegar al límite de filas por hoja de Excel.

    #759 (incidencia en GitHub)
  • CambiadoFuncionaDivide las hojas Findings y Pages de report-build en el límite de filas de Excel y#759

    emite un índice con hash…

    Divide las hojas Findings y Pages de report-build en el límite de filas de Excel y emite un .xlsx.index.json con hash, que incluye los rangos exactos de registros, la población de origen y las referencias de selección y de cobertura. Conserva el informe anterior ante fallos de escritura capturados y limpia los spools de streaming al interrumpirse.

    #759 (incidencia en GitHub)
  • CambiadoFuncionaRechaza celdas XLSX de más de 32 767 caracteres antes de que la biblioteca las trunque…#759

    Rechaza celdas XLSX de más de 32 767 caracteres antes de que la biblioteca de hojas de cálculo pueda truncarlas, protege los metadatos de Summary frente a la inyección de fórmulas y rechaza filas de auditoría conservadas malformadas antes de que una exportación incompleta pueda declararse correcta. Las exportaciones CSV y JSON completas y la política acotada de resumen en PDF siguen disponibles.

    #759 (incidencia en GitHub)
  • AñadidoFuncionaAñade entrega acotada de CSV de BI seleccionado con contabilidad exacta de filas de#759

    origen, seleccionadas y omitidas…

    Añade entrega acotada de CSV de BI seleccionado, con contabilidad exacta de filas de origen, seleccionadas y omitidas, cobertura de origen conservada, hashes calculados en flujo y un índice durable de rangos de CSV a hoja de XLSX. Las celdas de Excel demasiado grandes fallan antes de truncarse, y una salida interrumpida no se marca como completa.

    #759 (incidencia en GitHub)
  • CambiadoFuncionaConserva filas completas e inmutables de cobertura de comprobaciones junto a las#759

    exportaciones BI de hallazgos seleccionados, incluidos los motivos de las comprobaciones omitidas, y admite la selección exacta de hallazgos por segmento conservado del alcance de rastreo.

    #759 (incidencia en GitHub)
  • AñadidoFuncionaAñade diagnósticos de rastreo sin conexión para escaneos nativos guardados y artefactos#758

    de ejecuciones antiguas…

    Añade diagnósticos de rastreo sin conexión para escaneos nativos guardados y artefactos de ejecuciones heredadas, con evidencia de decisión acotada, explicaciones accionables, acceso de solo lectura por CLI y MCP, y un comando o herramienta de exportación redactada aparte, de activación voluntaria.

    #758 (incidencia en GitHub)
  • AñadidoFuncionaAñade vistas versionadas de hallazgos de proyecto con filtros cerrados y orden por#757

    gravedad…

    Añade vistas versionadas de hallazgos de proyecto con filtros cerrados, ordenación por gravedad, proyección de columnas y paginación acotada. Al ordenar por gravedad descendente, los hallazgos críticos aparecen primero; en orden ascendente va de aviso a crítico. CLI, MCP, los informes y la futura navegación en terminal pueden reutilizar la misma vista de solo lectura sin cambiar la evidencia de origen, la puntuación, las tareas ni la cobertura.

    #757 (incidencia en GitHub)
  • AñadidoFuncionaAñade planificación de monitorización local, desactivada por defecto, con presupuestos#756

    incrementales y completos…

    Añade planificación de monitorización local, desactivada por defecto, con presupuestos explícitos incrementales y de actualización completa, rechazo de solapamientos, reclamaciones de recuperación, procedencia inmutable de observaciones, retención de resultados parciales y alertas y avisos de recuperación deduplicados. El monitor no inicia ningún temporizador, rastreo ni canal de entrega.

    #756 (incidencia en GitHub)
  • AñadidoFuncionaAñade un adaptador de entrega de servicio inyectado y explícito para avisos completos de#756

    monitor conservados.

    Requiere un destino autorizado y vinculado al proyecto, además de un almacén de recibos duradero. No se activa por defecto ningún transporte, cuenta, temporizador ni destino.

    #756 (incidencia en GitHub)
  • CambiadoFuncionaHace seguras ante reinicios las reclamaciones de monitorización, la cobertura y la#756

    procedencia de caché…

    Hace seguras ante reinicios las reclamaciones de monitorización conservadas, la cobertura, la procedencia de caché, la evidencia de recuperación derivada y la entrega opcional de servicio.

    #756 (incidencia en GitHub)
  • AñadidoFuncionaAñade un recolector de monitor de una sola ejecución, explícito y acotado por lease, con#756

    evidencia consciente de la caché…

    Añade un recolector de monitor de una sola ejecución, explícito y acotado por lease, con evidencia conservada que tiene en cuenta la caché y recibos de entrega solo locales.

    #756 (incidencia en GitHub)
  • AñadidoFuncionaAñadidos verify-fixes / seo_verify_fixes para volver a comprobar URL seleccionadas#755

    Añadido verify-fixes / seo_verify_fixes para volver a comprobar, de forma acotada, URL seleccionadas a partir de IDs de incidencias guardados, de una vista de verificación o de una lista explícita de URL. Reutiliza la política de rastreo registrada y escribe un artefacto de verificación independiente, que no sobrescribe nada, con su informe enfocado. Distingue entre incidencias resueltas, persistentes, cambiadas y no verificables. Una auditoría after existente solo puede verificarse sin acceso a la red si tiene un UUID de escaneo propio y una hora de observación registrada posterior; las mediciones no realizadas o la evidencia de todo el sitio nunca se marcan como corregidas.

    #755 (incidencia en GitHub)
  • CambiadoFuncionaFiltrado de rutas nativas por extensión y Content-Type antes de procesarlas#749

    Los rastreos nativos por URL pueden filtrar las rutas descubiertas por la extensión final del nombre de archivo antes de hacer peticiones, y por el Content-Type real de la respuesta antes de analizarla o conservar el cuerpo. Ambas fases de filtrado registran sus decisiones y conservan la evidencia de enlaces, estados, cabeceras y redirecciones; los metadatos HTML de las páginas filtradas siguen marcados explícitamente como no medidos. Los recursos de scripts y hojas de estilo mantienen su selección y sus presupuestos de bytes independientes.

    #749 (incidencia en GitHub)
  • CambiadoFuncionaCobertura explícita cuando no hay cuerpo HTML disponible#749

    Cuando no hay cuerpo HTML disponible, las incidencias que dependen del cuerpo conservan ahora una cobertura omitida explícita, en lugar de tratar los valores por defecto del parser como limpios o como metadatos ausentes observados.

    #749 (incidencia en GitHub)
  • AñadidoFuncionaExclusiones auditables por patrón de URL en las incidencias#748

    Las incidencias suprimidas se mantienen en el JSON de auditoría y en las exportaciones de report-build, con la regla que coincide y el motivo, mientras que los totales de incidencias activas, la puntuación y el backlog de tareas reflejan la política configurada. Los artefactos de escaneo nativos conservan la política para el reanálisis sin conexión; el número de reglas y la longitud de los campos están acotados.

    #748 (incidencia en GitHub)
  • AñadidoFuncionaAñadido scan-export (seo_scan_export): exportación offline de datos de escaneo#747

    Añade scan-export (seo_scan_export): una exportación de datos de escaneo de solo lectura y sin conexión, bajo el contrato versionado scan_export.v1. Lee un artefacto SQLite scan.v1 validado o un audit.json de SF Analyzer, y escribe CSV (un archivo por tipo de registro más un manifiesto), XLSX (libro de solo escritura), un envoltorio JSON en streaming o un documento XML documentado. Cada salida incluye procedencia, número de filas exportadas, estadísticas de ejecución y cobertura explícita (qué comprobaciones se ejecutaron, se omitieron, se desactivaron o quedaron sin contabilizar), y ninguna de ellas puede eliminarse con la selección de campos. --records y --fields ofrecen una proyección validada de los registros de página, enlaces e incidencias; los tipos de registro o nombres de campo desconocidos se rechazan antes de crear cualquier archivo de salida. Los valores ausentes se mantienen explícitos (null en JSON, state="absent" en XML, \N en CSV/XLSX) en lugar de convertirse en ceros inventados. La salida XML es una serialización generada con escape UTF-8 correcto; nunca interpreta XML, DTD, hojas de estilo ni entidades aportadas por el usuario. CSV y XLSX mantienen la defensa existente contra inyección de fórmulas; XLSX rechaza los desbordamientos de filas, columnas y texto de celda de Excel en lugar de truncar, y cualquier fallo de serialización no deja ningún artefacto parcial que parezca válido.

    #747 (incidencia en GitHub)
  • CambiadoFuncionacrawl-site comprueba de forma opcional los destinos externos registrados#746

    crawl-site añade una comprobación opcional y acotada de los destinos externos registrados: discovery.external.crawl ejecuta una fase separada tras cerrar la frontera interna, y pide cada destino de enlace saliente distinto una sola vez, con sus propios presupuestos external_checks.max_targets/max_hosts/max_requests/max_depth/max_redirects; nunca hay recorrido recursivo fuera del host. Los resultados (obtenido, fallido, bloqueado u omitido con la regla que lo rechazó) se añaden a external_checks.jsonl en el directorio de ejecución, conservan la procedencia de la página de origen, persisten al reanudar sin reabrir presupuestos agotados e informan de su propia cobertura en discovery.external_checks, separada de la completitud del rastreo interno. Requiere discovery.external.store; se rechaza explícitamente en la ruta SQLite nativa (--scan-out) hasta que ese colector incorpore esta fase.

    #746 (incidencia en GitHub)
  • AñadidoFuncionaProxy HTTP de reenvío con política explícita y validada para el rastreo nativo#745

    Añade una política explícita y validada de proxy HTTP de reenvío para el rastreo nativo, que cubre las peticiones de páginas, sitemaps, recursos y del navegador fijado, con procedencia de ruta redactada.

    #745 (incidencia en GitHub)
  • CambiadoFuncionaEl renderizado nativo permite elegir el motor del navegador#744

    El paso de renderizado del rastreador nativo expone ya su navegador mediante configuración, en lugar de tener Chromium fijo en el código. rendering.browser.engine elige chromium (sigue siendo el valor por defecto), firefox o webkit a través de la misma ruta protegida de Playwright. Un nombre desconocido falla al validar la configuración, no al lanzar el navegador, y un motor solicitado cuyo binario no está instalado informa de un error de dependencia que indica la solución (playwright install <engine>), en lugar de caer en silencio a Chromium. La limitación documentada de Firefox se aplica de forma honesta: rechaza rendering.browser.mobile_emulation (is_mobile no se soporta allí), mientras que la opción independiente rendering.browser.touch_emulation (has_touch) sigue llegando al contexto. Las sondas y los renderizados completos comparten una única configuración efectiva, así que un patrón nunca se escala con un navegador distinto del que generó su evidencia.

    #744 (incidencia en GitHub)
  • CambiadoFuncionarendering.browser.viewport_width y rendering.browser.viewport_height añaden viewports#744

    a medida

    rendering.browser.viewport_width y rendering.browser.viewport_height añaden dimensiones de viewport arbitrarias junto a los presets existentes desktop/mobile, que siguen determinando el perfil como antes. El par es de todo o nada y está acotado a 1..16384 px; un par personalizado reemplaza solo las dimensiones del preset y no implica emulación móvil ni táctil, que siguen siendo indicadores explícitos que debe establecer quien opera.

    #744 (incidencia en GitHub)
  • CambiadoFuncionarendering.browser.page_concurrency limita las peticiones de navegador en vuelo#744

    rendering.browser.page_concurrency limita cuántas peticiones de navegador pueden estar en vuelo durante la escalada, por separado de speed.concurrency, que sigue regulando la cortesía del rastreo HTTP. El valor por defecto, 1, conserva el comportamiento secuencial y no crea ningún pool; por encima de 1, las sondas y los renderizados se ejecutan en un pool de workers acotado, mientras que cada veredicto, confirmación y escritura en SQLite se mantiene en el hilo orquestador y en el orden de envío. El plazo de renderizado, el presupuesto de URL y las políticas de muestreo y completas se mantienen con concurrencia; un lote detenido espera a las páginas que ya inició y nunca programa nuevas; los workers interrumpidos o fallidos no dejan ningún hilo, página, contexto ni navegador activos tras la llamada.

    #744 (incidencia en GitHub)
  • CambiadoFuncionaEl motor, su versión y el viewport efectivo quedan registrados en el manifiesto#744

    El motor seleccionado, su versión real informada, el viewport efectivo y la concurrencia de página configurada se registran en el manifiesto del rastreo, en su huella y en la procedencia del renderizador de cada documento renderizado, incluidos los intentos fallidos, que registran lo solicitado sin inventar un renderizado correcto. Ambas rutas de escalada respetan la configuración: el rastreo por directorio y el escaneo nativo SQLite, donde los candidatos de enlaces renderizados entran en la frontera mediante la admisión deduplicadora existente una vez activo rendering.rendered_links.crawl.

    #744 (incidencia en GitHub)
  • AñadidoFuncionaComprobaciones opcionales de canonical para patrones de paginación y filtros#727

    Añade comprobaciones opcionales de la política canonical para los patrones de URL de paginación y de filtros configurados, tanto en el pipeline de exportación de SF como en el de auditoría del rastreo nativo. Las reglas de paginación admiten como destino la propia página, la primera página o la página de aterrizaje; las reglas de filtros admiten la propia página o la página de aterrizaje. Las políticas ausentes y los destinos que no aparecen en la evidencia del rastreo siguen sin medir, y las comprobaciones de código de estado del destino se mantienen separadas.

    #727 (incidencia en GitHub)
  • AñadidoFuncionaArchivos reanudables de GSC Search Analytics en el histórico local de proveedores#718

    Añade archivos reanudables de GSC Search Analytics en el almacén SQLite local compartido de histórico de proveedores, accesibles de forma coherente mediante gsc-archive y seo_gsc_archive. El estado sin conexión, la preparación explícita, la recogida acotada y las instantáneas verificadas comparten un mismo núcleo.

    #718 (incidencia en GitHub)
  • CambiadoFuncionaProcedencia de proveedor y motor, métricas que pueden ser nulas y reintentos acotados#718

    Conserva la procedencia de proveedor y motor y las métricas que pueden ser nulas, encola solo los rangos de disponibilidad sin cubrir y persiste las esperas por cuota y los reintentos transitorios acotados.

    #718 (incidencia en GitHub)
  • AñadidoFuncionaHistórico SQLite local y versionado para GA4, Metrika, GSC y Yandex Webmaster#716

    Añade un histórico SQLite local y versionado para los datos diarios de GA4, Metrika, consultas y páginas web de GSC y Yandex Webmaster, con reemplazo atómico por día y cobertura explícita: solicitado, vacío, parcial, fallido y con retraso.

    #716 (incidencia en GitHub)
  • AñadidoFuncionaSincronización acotada, estado offline y exportación JSON/CSV en la CLI y el MCP#716

    Expone la sincronización acotada y determinista, el estado sin conexión y la exportación JSON/CSV a través de la CLI compartida y del MCP local, incluidas la aditividad de métricas y los metadatos conservadores de zona horaria. No se almacenan credenciales ni datos de proveedores en el repositorio.

    #716 (incidencia en GitHub)
  • CambiadoFuncionaEl modo A de SF verifica las exportaciones antes de analizar#715

    El modo A de SF verifica ahora las capacidades de exportación que solicita la CLI instalada y exige un conjunto completo y reciente de exportaciones antes de analizar. La procedencia del perfil completo registra el manifiesto de exportación verificado y la lectura de la velocidad de rastreo; un límite de velocidad explícito falla antes de rastrear si su configuración base falta o no es válida.

    #715 (incidencia en GitHub)
  • CambiadoFuncionaReintentos por tramos mensuales en metrika-report (seo_metrika_report) y#714

    MetrikaClient.report()

    metrika-report (seo_metrika_report) y MetrikaClient.report(): un rechazo de la Reporting API por «Query is too complicated» se reintenta ahora por tramos mensuales, con una espera de 5 a 15 s; un tramo que sigue rechazándose se vuelve a enviar con accuracy=0.1 muestreado. Solo se combinan las métricas demostrablemente aditivas sobre periodos disjuntos (ym:s:visits, ym:s:pageviews): una consulta de visitantes únicos, porcentajes, medias o métricas no verificables se rechaza antes de la primera petición de tramo, en lugar de devolver un valor sumado que sería incorrecto. Los tramos se combinan a medida que llegan bajo un único límite global de filas que también acota las descargas: una vez agotado, las particiones restantes nunca se piden y sus intervalos de fechas se nombran en split.unfetched; un tramo interrumpido a mitad lista su propio intervalo allí con partial. Los totales total_rows/totals de todo el periodo siguen desconocidos cuando los periodos no consultados los hacen incognoscibles, y la ventana devuelta se marca como parcial. Las respuestas combinadas vuelven a aplicar el sort de quien llama (dimensiones y métricas, o el orden por defecto de la API: primera métrica descendente), y la ventana offset/limit se toma del conjunto global combinado. Los campos de muestreo reflejan lo que la API informó realmente (sampled, peor sample_share); un tramo que no los informa deja el valor de todo el periodo como desconocido: null en la respuesta de CLI/MCP, nunca un false inventado. contains_sensitive_data es el OR de los tramos, min/max se recalculan sobre las filas combinadas, y las celdas o totales de métricas ausentes o malformados marcan el cuerpo como incomplete en lugar de leerse como cero. El bloque split conserva los periodos solicitados y resueltos, la zona horaria usada y, por tramo, la precisión, los intentos, las filas descartadas y los metadatos de muestreo; una partición que falla nombra los intervalos completados y las precisiones agotadas. Las fechas relativas (today, NdaysAgo) se resuelven en la timezone de la petición o en la zona del propio contador (time_zone_name, o si no su desfase en minutos), nunca en la fecha del host. Un periodo que no puede convertirse en fechas (un atajo como month) se sigue reintentando y muestreando antes de relanzar el error. Una accuracy explícita se respeta en todas las formas documentadas (low/medium/high/full o una proporción numérica como "1"): cualquier valor por encima del último recurso de muestreo mantiene el fallback accuracy=0.1, mientras que un ajuste ya más bajo de quien llama (low o una proporción igual o inferior) se conserva en lugar de remuestrearse hacia arriba. Cada petición intentada, incluida la llamada global rechazada, llega al diario de gasto.

    #714 (incidencia en GitHub)
  • CambiadoFuncionaYandex Webmaster: la operación indexing usa el endpoint v4 real#713

    Yandex Webmaster: la operación indexing lee ahora el endpoint real v4 /indexing/samples en lugar del inexistente /search-urls; la nueva broken_links_samples lee /links/internal/broken/samples, y la paginación respeta el límite de tamaño de página documentado de cada endpoint (500 para consultas, 100 para las listas de muestras), en lugar de enviar limit=500 en todas partes (#713).

    #713 (incidencia en GitHub)
  • CambiadoFuncionaYandex Webmaster valida el count y la forma de cada página#713

    La recogida paginada de Yandex Webmaster valida ahora el count documentado de cada página y la forma de su lista, incluido un count menor que las filas devueltas. Pide en cada página como máximo el presupuesto de filas restante, de modo que un corte por max_rows nunca lea de más y produzca un complete falso; expone returned/truncated para una única página no paginada como un fragmento acotado; informa de partial siempre que queden filas sin leer, y falla las páginas malformadas en lugar de afirmar un resultado vacío y completo (#713).

    #713 (incidencia en GitHub)
  • CambiadoFuncionaRender-check usa la confianza de la plataforma más una CA explícita#709

    Render-check usa la confianza de la plataforma más una CA seleccionada explícitamente, reproduce las subpeticiones POST fijadas e informa de los fallos de verificación de certificados sin detalles del transporte.

    #709 (incidencia en GitHub)
  • CambiadoFuncionaReconoce el fallo TLS del proxy fijado y verifica la CA de fixture explícita#709

    Reconoce el fallo de verificación TLS del transporte proxy fijado y verifica, mediante un interceptor CONNECT sintético propio, la confianza explícita en la CA de fixture, la repetición de POST, los límites de respuesta y el rechazo de destinos privados, sin cambiar la confianza de la plataforma.

    #709 (incidencia en GitHub)

3 de octubre de 2026

5 añadido8 cambiado1 corregido
  • AñadidoFuncionaAñadido crawl-import para paquetes CSV de rastreos de terceros con mapeo explícito#819

    Añade crawl-import para paquetes CSV de rastreos de terceros con mapeo explícito. Conserva la identidad de la fuente externa, la cobertura por campo, las observaciones duplicadas y los datos no disponibles en third_party_crawl.v1, sin tratar el resultado como un escaneo nativo ni como una auditoría de SF.

    #819 (incidencia en GitHub)
  • AñadidoFuncionaTransporte remoto opcional de Playwright con endpoint y versión explícitos#808

    Añade un transporte remoto opcional de navegador Playwright con endpoint explícito y comprobaciones de versión, estados de fallo seguros y ningún recurso de lanzamiento local, manteniendo los valores por defecto del renderizado local.

    #808 (incidencia en GitHub)
  • AñadidoFuncionaConsultas de ruta observada más corta y de enlaces entrantes inversos#805

    Añade consultas Python de solo lectura, acotadas y deterministas, para la ruta observada más corta y los enlaces entrantes inversos sobre los enlaces de escaneo conservados, con la identidad del registro de escaneo en cada salto y cobertura explícita de grafo parcial.

    #805 (incidencia en GitHub)
  • CambiadoFuncionaRegresión de enrutamiento de proveedores alineada con la petición Wordstat de Arsenkin#779

    Alinea la regresión de enrutamiento de proveedores con el contrato corregido de la petición de frecuencia Wordstat de Arsenkin (#720, #779).

    #779 (incidencia en GitHub)
  • AñadidoFuncionaAñadido docs/PROVIDERS.md: matriz generada de capacidades de proveedores#779

    Añade docs/PROVIDERS.md, una matriz generada de capacidades de proveedores y de flujos de trabajo especializados (#779, épica #753). Se genera a partir del registro de proveedores activo y de un catálogo curado de flujos en seohead/core/provider_matrix.py, mediante scripts/generate_provider_matrix.py. Registra, por flujo, los comandos disponibles, la autenticación, el coste y la cuota, la clase de privacidad, las limitaciones y el fallback CSV mediante provider-join. Los estados distinguen entre soportado, parcial, no soportado y no verificado; ningún proveedor declarado aparece como verificado en vivo, el trabajo explícitamente no soportado se lista por nombre, y la primera versión se selecciona por fases sin afirmar que cubre todos los servicios. Las discrepancias entre el documento confirmado y los registros las detectan tests/test_docs_drift.py y tests/test_provider_matrix.py.

    #779 (incidencia en GitHub)
  • CorregidoFuncionaCorregido keywords-exact / seo_keywords_exact, que nunca devolvía resultados#720

    Corregido keywords-exact / seo_keywords_exact, que nunca podía devolver un resultado: la tarea se creaba para una herramienta de Arsenkin llamada keywords_frequency que no existe, así que cada llamada respondía 404 WRONG_TOOL. El !W exacto va ahora a la herramienta wordstat con type=1, el array de frases bajo queries y la región como lista de un solo elemento.

    #720 (incidencia en GitHub)
  • CambiadoFuncionaPide el selector overal para !W: los valores ws de Arsenkin son operadores distintos#720

    Solicita el selector overal para !W: los valores ws de Arsenkin son operadores distintos. base es amplio (WS), quoted es la frase entre comillas («WS»), overal es la forma exacta de palabra (!WS) que pide !W, y exact es la forma de orden estricto ([!WS]).

    #720 (incidencia en GitHub)
  • CambiadoFuncionaElimina antes de enviar la puntuación que el proveedor rechaza, como el /#720

    Elimina antes de enviar la puntuación que el proveedor rechaza: una sola frase con / o comillas hacía que rechazara todo el lote con 422 JSON_VALIDATION_ERROR. Las frases reescritas se devuelven en cleaned, para que quien llama vea cuáles se midieron en otra forma.

    #720 (incidencia en GitHub)
  • CambiadoFuncionaDevuelve frequencies como {phrase: {"base": N, "overal": N}} junto a la respuesta#720

    bruta del proveedor. Una frase cuyo resultado solo nombra otras regiones se omite y se lista en warnings, en lugar de tomar prestadas las cifras de otra región.

    #720 (incidencia en GitHub)
  • AñadidoFuncionaAcceso de solo lectura a Topvisor desde la CLI y el MCP#719

    Añade acceso de solo lectura y acotado a Topvisor a través de la CLI compartida y del handler MCP, con archivos de credenciales centralizados, paginación explícita y sin operaciones de pago por comprobación.

    #719 (incidencia en GitHub)
  • CambiadoFuncionaAlinea el bloque sources.gsc de sources-doctor con provider_status.gsc#717

    Alinea el bloque heredado sources.gsc de sources-doctor con provider_status.gsc: ready y el nuevo campo components ahora salen de los mismos componentes de credencial (token bearer de OAuth, concesión duradera o cuenta de servicio), en lugar de mirar solo el archivo bearer. Por eso una cuenta de servicio configurada ya no aparece como «GSC no está configurado». El componente de cuenta de servicio valida ahora el propio documento JSON (archivo regular privado, tamaño acotado, tipo service_account, la URI de token de Google exacta y los campos obligatorios), y ambos bloques de doctor informan de un valor seguro service_account_status (missing, unsafe_file, too_large, unreadable, malformed_json, unsupported_shape o configured_unverified). Así, un archivo demasiado grande, ilegible o malformado se distingue de uno configurado pero sin verificar, sin exponer su contenido.

    #717 (incidencia en GitHub)
  • CambiadoFuncionacrawl-site marca finished_at y el ciclo finished cuando la cola termina#712

    Los artefactos de escaneo de crawl-site registran ahora finished_at y un ciclo de vida finished cuando cada fila de frontera aceptada alcanza un estado terminal, incluidas las ejecuciones cuya evidencia conservada es parcial: crawl_partial ya nombra las observaciones omitidas, así que una cola vaciada ya no aparece como captura interrumpida en scan-status, scan-list ni en el histórico (#712). Una ejecución detenida explícitamente —abortada antes de aceptar trabajo, cancelada o detenida por el circuito de errores— conserva interrupted y su motivo registrado incluso después de vaciar la cola, también a través de resume_or_finalize, de modo que las rutas de parada nunca reciben una marca de finalización falsa.

    #712 (incidencia en GitHub)
  • CambiadoFuncionaduplicate-check --scan y boilerplate-report --scan procesan corpus de tamaño normal#710

    duplicate-check --scan y boilerplate-report --scan ahora procesan en streaming un corpus conservado en lugar de fallar en sitios de tamaño normal: el plazo de apertura y validación del escaneo se calcula según el tamaño del artefacto, y cada lectura de documento tiene su propio plazo, de modo que un corpus de 1500 páginas ya no termina en interrupted. El presupuesto de bytes de entrada del corpus mide lo que el analizador retiene realmente (Markdown extraído para duplicados, un digest por página para el boilerplate), no el tamaño del HTML bruto; al alcanzar un límite del corpus se informa cobertura parcial con los recuentos exactos de preparados y elegibles, y el límite que detuvo la lectura (#710).

    #710 (incidencia en GitHub)
  • CambiadoFuncionareport() y by_time() de Metrika rechazan offset < 1 en local con un ValueError#707

    report() y by_time() de Metrika rechazan ahora offset < 1 en local con un ValueError, en lugar de reenviarlo a la Reporting API, que responde offset=0 con HTTP 400. Nuevas pruebas sin conexión fijan el contrato base 1 en metrika-report, seo_metrika_report y aggregate_report de provider-collect, y verifican que las condiciones de parada paginadas (total_rows, ROW_CAP) cuentan las filas saltadas antes de un offset no predeterminado (#707).

    #707 (incidencia en GitHub)

2 de octubre de 2026

1 añadido2 cambiado
  • CambiadoFuncionametrika-traffic-pdf en macOS: Chrome ya no bloquea la generación del PDF#731

    metrika-traffic-pdf en macOS: Chrome escribe el PDF y sigue ejecutándose; el navegador ahora se inicia sin esperar y se detiene una vez verificado el PDF.

    #731 (incidencia en GitHub)
  • CambiadoFuncionaYandex Webmaster: user_id sale del token y hay nuevas operaciones de solo lectura#713

    Yandex Webmaster: user_id se resuelve a partir del token; nuevas operaciones de solo lectura summary, diagnostics, sqi_history, search_history, query_history, in_search_history, events_history, indexing_history, important_urls, broken_links_history, external_links_history; params para fechas e indicadores; paginación de las listas de consultas y de muestras de rastreo (#713).

    #713 (incidencia en GitHub)
  • AñadidoFuncionaNueva skill técnica traffic-report: informe de tráfico mensual o anual para el cliente

    Nueva skill técnica traffic-report: un informe mensual o anual para el cliente a partir de Metrika, Webmaster y Search Console (conversiones contadas como visitas, comprobaciones de coherencia de objetivos, productos, retrato del comprador y reglas para las diapositivas).

1 de octubre de 2026

1 añadido1 cambiado
  • AñadidoFuncionaAñadido metrika-traffic-pdf (seo_metrika_traffic_pdf): informe de tráfico en PDF#731

    Añade metrika-traffic-pdf (seo_metrika_traffic_pdf): un informe de tráfico estático en A4 apaisado, con el diseño de un panel analítico, generado a partir de Yandex Metrika. La recogida y el renderizado son etapas separadas. La recogida lee la Reporting API (unas 40 peticiones sin coste, de solo lectura) y la agrupa en un único documento seohead.metrika-traffic/1: nueve tarjetas de KPI (usuarios, visitas, páginas vistas, páginas por visita, visitas por día, porcentaje de rebote, duración media de la visita, porcentaje de visitantes con dos o tres visitas y porcentaje de visitantes nuevos), con variaciones respecto al periodo anterior de igual duración y a las mismas fechas un año antes; la dinámica diaria; ventanas de 3, 6 y 12 meses frente a las ventanas anteriores; buscadores, ciudades, países, dispositivos, edad, sexo, principales páginas de aterrizaje y frases de búsqueda; y todos los canales de tráfico. El renderizado convierte ese documento en HTML autocontenido con gráficos SVG en línea y lo imprime a PDF mediante Chrome, Edge o Chromium instalados localmente (SEOHEAD_CHROME tiene prioridad en la búsqueda). La marca (nombre, colores, pila tipográfica, texto del logotipo) y las etiquetas en inglés o ruso son entradas; las filas de consultas de Search Console pueden añadirse como página opcional. La atribución por defecto es el último origen significativo (ym:s:lastSignTrafficSource y sus dimensiones de motor y frase), que es lo que muestra la interfaz de Metrika; las dimensiones de último clic difieren de ella en unos pocos por ciento y siguen disponibles como attribution=last_click explícito. Cada petición incluye offset=1, porque la API cuenta las filas desde 1. Los datos ausentes se mantienen visibles: cada bloque lleva ok, unavailable o skipped con un motivo; un cambio sin base de comparación es null y no cero; si falta el navegador, el HTML se genera pero el PDF se marca como omitido; y los archivos existentes en out_dir solo se reemplazan con overwrite=true.

    #731 (incidencia en GitHub)
  • CambiadoFuncionaLos informes de Metrika empiezan en offset=1: la Reporting API cuenta desde 1 y#707

    respondía con HTTP 400 a cada petición enviada con offset=0 (#707, #728, #729).

    #707 (incidencia en GitHub)

26 de septiembre de 2026

1 añadido
  • AñadidoFuncionaEvidencia HEADING_SKIP para saltos de nivel H1–H6 en el rastreo nativo#725

    Añade evidencia HEADING_SKIP en el rastreo nativo para los saltos de nivel H1–H6 en la región de contenido nombrada. Se excluyen los encabezados de cabecera, pie, navegación, barra lateral y los ocultos explícitamente o en diálogos cerrados, para que la interfaz de la plantilla no genere una jerarquía falsa. Las ejecuciones solo de exportación de Screaming Frog marcan esta comprobación como no disponible.

    #725 (incidencia en GitHub)

23 de septiembre de 2026

1 cambiado
  • CambiadoFuncionaArchivos secretos privados en Windows y consentimiento de Search Console#708

    Acepta archivos secretos privados en Windows, donde no existen los bits de permisos POSIX, y añade un script de consentimiento en el navegador que guarda una concesión de solo lectura para Search Console.

    #708 (incidencia en GitHub)

13 de septiembre de 2026

2 añadido3 cambiado2 corregido
  • AñadidoFuncionaSoporte para SQLite nativo en Windows#705

    Soporte para escritores SQLite nativos, histórico, reintentos, instantáneas, reanálisis y publicación de proyectos en Windows, con bloqueos de rango de bytes respaldados por el sistema operativo y comprobaciones portables de espacio libre. Se mantiene el vaciado de directorios POSIX; el vaciado de archivos en Windows y la publicación atómica siguen disponibles sin garantía de fsync de directorio POSIX. Los flujos portables se ejecutan en el CI de Windows y en un entorno Linux aislado.

    #705 (incidencia en GitHub)
  • CorregidoFuncionaCompatibilidad del escaneo HTML con versiones antiguas de Python#705

    Mantiene el escaneo de HTML en texto plano compatible con versiones de Python que no tienen la opción de scripting más reciente de HTMLParser, incluida la distribución de Python 3.12 para Windows.

    #705 (incidencia en GitHub)
  • CorregidoFuncionaGuías de datos estructurados y Googlebot corregidas y citadas#704

    Corrige y cita con fuentes las guías de Google sobre datos estructurados y Googlebot, incluidas la disponibilidad de FAQ/HowTo y las consecuencias de la política de datos estructurados.

    #704 (incidencia en GitHub)
  • CambiadoFuncionaDescubrimiento de sitemaps desde robots.txt, con /sitemap.xml como alternativa#703

    Descubre los sitemaps desde la raíz del sitio a través de robots.txt, con /sitemap.xml como alternativa, e informa de una expansión de sitemaps en la que todo ha fallado como ok: false.

    #703 (incidencia en GitHub)
  • CambiadoFuncionaReanudación del rastreo nativo tras cookies anónimas#702

    Permite reanudar el rastreo nativo tras cookies anónimas establecidas por el servidor, y registra la sesión nueva sin conservar los valores de las cookies; los rastreos con credenciales o con perfil persistente siguen sin poder reanudarse.

    #702 (incidencia en GitHub)
  • CambiadoFunciona--scan para rutas de escaneo guardadas y --input para JSON en línea#701

    Estandariza las rutas de escaneo guardadas como --scan y el JSON en línea como --input; los usos heredados de --input y --json-input con rutas de escaneo siguen funcionando durante una versión, con aviso.

    #701 (incidencia en GitHub)
  • AñadidoFuncionaConfirmación explícita para conservar evidencia anónima no-store#700

    Añade una confirmación explícita, desactivada por defecto, para conservar evidencia anónima acotada con Cache-Control: no-store, mientras se siguen omitiendo los cuerpos con credenciales.

    #700 (incidencia en GitHub)

9 de septiembre de 2026

10 añadido9 cambiado2 corregido
  • AñadidoFuncionaVistas previas offline de prioridades y aplicación explícita de políticas#694

    Añade vistas previas offline de prioridades del proyecto y aplicación explícita y versionada de políticas, usando los hechos de stack guardados. Conserva las decisiones del operador, un histórico atómico de políticas y las explicaciones de prioridad coincidentes en los informes para personas.

    #694 (incidencia en GitHub)
  • CorregidoFuncionaCorrige las guías de renderizado JavaScript, canonical, URL y notranslate#692

    Corrige las recomendaciones sobre renderizado de JavaScript, canonical, higiene de URL y notranslate, sin cambiar las comprobaciones en tiempo de ejecución ni las severidades.

    #692 (incidencia en GitHub)
  • CorregidoFuncionaLa fixture de documentación usa el origen loopback efímero#690 (incidencia en GitHub)
  • AñadidoFuncionaChecklist de proyecto portable con catálogo empaquetado#686

    Añade cobertura portable de checklist de proyecto con un catálogo empaquetado derivado de las fuentes, plantillas personalizadas reutilizables, histórico de definiciones y de evidencias, escrituras concurrentes optimistas, revisión manual y de entregables explícita, y vistas offline de pendiente, obsoleto y bloqueado. Las comparten la CLI, el MCP y los informes humanos vinculados a proyectos.

    #686 (incidencia en GitHub)
  • AñadidoFuncionaResumen de estado de escaneo nativo de solo lectura#685

    Añade un resumen de estado de escaneo nativo, de solo lectura, para las poblaciones de la frontera y los resultados HTTP confirmados.

    #685 (incidencia en GitHub)
  • AñadidoFuncionaEspacios de trabajo de proyecto locales y portables#678

    Añade espacios de trabajo de proyecto locales y portables, con estados explícitos de checklist pendiente y de preparación.

    #678 (incidencia en GitHub)
  • AñadidoFuncionaRevisión de la guía de Google Search Central: 175 guías leídas y tres correcciones#677

    Registra en el repositorio la revisión de la guía de Google Search Central: 175 guías leídas, sus etiquetas, exclusiones, fecha de la instantánea y las tres correcciones que produjo.

    #677 (incidencia en GitHub)
  • CambiadoFuncionaEn modo URL, crawl-site escribe un escaneo SQLite nativo a prueba de colisiones#676

    En modo URL, crawl-site escribe ahora por defecto un escaneo SQLite nativo a prueba de colisiones en el directorio scans/ de quien llama. --out-dir sigue siendo la ruta heredada y explícita de directorio, mientras que la entrada en lista y la configuración de caché live/replay indican esa ruta en lugar de cambiar el modo de recogida en silencio.

    #676 (incidencia en GitHub)
  • CambiadoFuncionaLas compilaciones limpias incrustan la procedencia validada del productor#675

    Las compilaciones de distribución limpias incrustan ahora la procedencia validada del productor en los escaneos SQLite nativos cuando no hay un checkout del código fuente disponible.

    #675 (incidencia en GitHub)
  • CambiadoFuncionaSustituidas las afirmaciones sin soporte sobre 301 y 302 en la skill de auditoría#671

    En la skill de auditoría incluida en el paquete, sustituye las afirmaciones sin soporte sobre pérdida de señal con 301 fijo y la ausencia categórica de autoridad de enlace con 302 por una guía basada en la intención permanente o temporal y en el destino canonical, citando Google Search Central. Las redirecciones temporales siguen siendo válidas para cambios temporales; un código de estado por sí solo no mide una pérdida de posicionamiento.

    #671 (incidencia en GitHub)
  • CambiadoFuncionarender-check --viewport mobile ahora usa una única identidad de diagnóstico estable#670

    para smartphone en sus solicitudes brutas y de navegador. Hay un --user-agent explícito disponible en CLI y MCP, y cada comparación completa o parcial registra la identidad efectiva y el tamaño del viewport.

    #670 (incidencia en GitHub)
  • AñadidoFuncionaAñade entradas --scan de solo lectura para el análisis de corpus de duplicados y#669

    boilerplate, con cobertura del cuerpo conservado y procedencia.

    #669 (incidencia en GitHub)
  • AñadidoFuncionaAñadido un catálogo generado de entradas de comandos y documentada la decisión sobre el#668

    almacén del escaneo, la caché HTTP y el diario de ejecuciones.

    #668 (incidencia en GitHub)
  • CambiadoFuncionaLos informes de cliente en Markdown, CSV, XLSX, DOCX y de tareas ahora usan títulos de#660

    hallazgo pensados para quien los lee…

    Los informes para el cliente en Markdown, CSV, XLSX, DOCX y de tareas ahora usan títulos de hallazgo pensados para quien los lee, y la reproducción guardada como evidencia, en lugar de identificadores del registro o nombres de colectores. Los registros históricos sin evidencia suficiente lo indican de forma explícita, y los artefactos de auditoría en JSON no cambian.

    #660 (incidencia en GitHub)
  • AñadidoFuncionaAñade project-facts para registrar los datos del stack tras crear el proyecto,#648

    opcionalmente desde una pasada…

    Añade project-facts para registrar los datos del stack del proyecto tras su creación, opcionalmente a partir de una única pasada explícita de tech-detect que respete robots.txt. Las decisiones introducidas por el operador prevalecen sobre la evidencia detectada, y una detección no disponible o ambigua queda sin registrar, con su motivo.

    #648 (incidencia en GitHub)
  • CambiadoFuncionaEmpieza el README por el controlador del proyecto y presenta Screaming Frog como segunda#648

    pasada de contraste, no como estándar de paridad.

    #648 (incidencia en GitHub)
  • AñadidoFuncionaIncluye examples/project-skeleton con una lista de comprobación inicializada y sin#648

    resultados, para que project status sobre él muestre recuentos de cobertura en lugar de not_initialized, y valida ese archivo contra el catálogo activo.

    #648 (incidencia en GitHub)
  • AñadidoFuncionaAñade contratos para la preparación del proyecto, la evidencia de proveedores, el corpus#354

    guardado, la extracción acotada, la evidencia de escaneo y el catálogo de workflows, con límites explícitos para la evidencia conservada y el progreso.

    #354 (incidencia en GitHub)
  • CambiadoFuncionaLos perfiles MCP y los wrappers de progreso que conservan metadatos requieren el SDK#354

    opcional de MCP 1.29…

    Los perfiles MCP y los wrappers de progreso que conservan metadatos requieren el SDK opcional de MCP en la versión 1.29 o posterior.

    #354 (incidencia en GitHub)
  • CambiadoFuncionaSimplificado el README en torno a los flujos de tarea → comando → artefacto, eliminados

    los embebidos visuales obsoletos y los contadores de marketing, y conservados los enlaces a las referencias generadas de la superficie de interfaz activa.

  • CambiadoFuncionaAmplía el README con flujos prácticos de entrada a resultado, con las llamadas CLI/MCP

    equivalentes y los límites precisos del corpus conservado y de los proveedores y el navegador.

8 de septiembre de 2026

8 cambiado2 corregido
  • CambiadoFuncionaReconcilia la documentación del artefacto SQLite con el cuerpo nativo entregado, el#666

    historial y…

    Reconcilia la documentación del artefacto SQLite con los contratos entregados de cuerpo nativo, historial y reanálisis sin conexión (#666). La tabla de campos de página tardía documentada ahora se contrasta con el mapeo del importador, de modo que una observación JSONL antigua sigue siendo SQL NULL y no se convierte en un valor limpio inventado.

    #666 (incidencia en GitHub)
  • CambiadoFuncionaLas auditorías nativas ahora señalan como omitidas las comprobaciones de meta keywords,#659

    canonical secundario, versión HTTP y amphtml cuando no se recopilaron sus campos de origen.

    #659 (incidencia en GitHub)
  • CorregidoFuncionaDeja de leer como credencial del operador una cookie que el propio sitio estableció en el#656

    carril de renderizado JavaScript, y avisa cuando una ejecución descarta los DOM renderizados (#656). Un navegador devuelve lo que la propia Set-Cookie del sitio le dio, así que en cuanto una página fijaba una cookie de sesión y después pedía un subrecurso del mismo origen (un script, una hoja de estilos, una imagen, la forma habitual de la web), el hook de solicitud del renderizador leía Cookie: de la red y guardaba el DOM serializado de esa página como omitted/credentialed, en una ejecución con http.credential_headers = []. Cada renderizado crea su propio contexto de navegador, así que la pérdida es por página y no acumulativa: cada página que fija una cookie pierde su propio DOM, y la ejecución informa de sus páginas, enlaces y recuentos de escalado exactamente como si fuera completa. Ahora credentials_used de un documento renderizado procede solo de lo que la ejecución está configurada para enviar (http.credential_headers o un perfil de navegador persistente), que es lo que crawl/sqlite_render.py::_policy_facts ya calcula y entrega al renderizador; este construye su propio cliente de red sin credencial, así que la red no tenía nada que añadir. Un rastreo con una credencial configurada sigue omitiendo esos DOM bajo credentialed, sin cambios, y el valor de la cookie nunca se almacena.

    #656 (incidencia en GitHub)
  • CambiadoFuncionaAhora se nombran los recuentos renderizados que una marca partial no puede transmitir.#656

    rendered_bodies en un resultado de crawl-site indica cuántos DOM renderizados se conservaron y el motivo de cada uno que no se conservó. La CLI lo imprime junto a la línea final, en lugar de dejarlo a un indicador de capacidad que dice «parcial» tanto por un DOM ausente como por todos. Una ejecución que no descartó nada no imprime nada extra. Los recuentos se leen de nuevo del artefacto de escaneo, de modo que un escaneo terminado sigue respondiendo a la misma pregunta después.

    #656 (incidencia en GitHub)
  • CambiadoFuncionaRecoge og:url en un rastreo nativo, en lugar de informar de que falta en cada página#654

    (#654).

    rules.check_og incluye og:url entre los missing_tags de una página siempre que el campo sea falso, y la ruta nativa nunca leía esa etiqueta: no había og_url en PageRecord, ni columna og_url en scan_v1.sql, ni OG:URL en la proyección Internal:All que construye crawl/evidence.py. La columna solo existía en el lado de Screaming Frog, donde normalize siempre había resuelto OG:URL, así que una exportación del sitio veía el valor real y un rastreo nativo del mismo sitio notificaba un defecto: un campo no medido presentado como medido, en cada página de cada rastreo nativo, fuera cual fuera el marcado. Ahora la etiqueta se lee donde se leen las otras tres (el parser ya la devolvía como og:url), se guarda en pages.og_url como columna anulable —anulable como todas las columnas añadidas después, para que un registro escrito antes de recogerla siga distinguiéndose de una página que no declara ninguna— y se proyecta como OG:URL. Es el lado de recogida de la costura que #646 corrigió en el lado de lectura. tests/test_open_graph_seam.py gana un tercer sitio de prueba cuyas páginas tienen Open Graph pero no og:title, de modo que el hallazgo se dispara de verdad y su lista se puede leer: una página declara og:url y no debe aparecer como que le falta, y la otra no lo declara y sí debe aparecer. La prueba que importa audita esas dos páginas dos veces, una desde el rastreo y otra desde una exportación Internal:All que describe las mismas dos páginas, y exige el mismo veredicto: #646 y #654 eran dos rutas que discrepaban sin ninguna prueba que las abarcara a ambas.

    #654 (incidencia en GitHub)
  • CorregidoFuncionaDeja de leer como credencial del operador una cookie que definió el sitio, y avisa cuando#647

    una ejecución descarta cuerpos (#647). Un rastreo comparte un único cliente HTTP, y ese cliente mantiene un cookie jar: en cuanto una respuesta traía Set-Cookie, todas las solicitudes posteriores salían con Cookie: y el escritor del corpus las clasificaba como descargas autenticadas. En un sitio público con http.credential_headers = [] y credentials_acknowledged = false, eso descartó 33 001 de 40 920 cuerpos de página, y la ejecución informó de sus páginas y enlaces exactamente como si estuviera completa. Todo lo calculado a partir del HTML almacenado en ese rastreo (detección de casi duplicados, profundidad y número de nodos del DOM, proporción de boilerplate, estructura de encabezados dentro del cuerpo, reanálisis sin conexión) abarcaba entonces 7 903 páginas, mientras que cada porcentaje a nivel de página del mismo informe abarcaba 40 920: dos poblaciones presentadas como una sola. Una captura es credentialed cuando la ejecución estaba configurada para enviar una cabecera de credencial para ese host, que es la única forma de que una cabecera sensible llegue a una solicitud que construye el rastreador (http.headers lo rechaza la validación de configuración). Un rastreo con una credencial configurada sigue omitiendo esos cuerpos bajo credentialed, sin cambios.

    #647 (incidencia en GitHub)
  • CambiadoFuncionaLos recuentos que una marca partial no puede transmitir ahora se nombran.#647

    html_bodies en un resultado de crawl-site indica cuántos cuerpos HTML de página descargados se conservaron y el motivo de cada uno que no se conservó. La CLI lo imprime junto a la línea final, en lugar de dejarlo a un indicador de capacidad que dice «parcial» tanto por un cuerpo ausente como por cuatro quintas partes de ellos. Una ejecución que no descartó nada no imprime nada extra. Las listas de cabeceras de solicitud y respuesta redactadas conservan ahora los nombres de las cabeceras que la redacción eliminó, bajo x-seohead-redacted-headers y nunca sus valores: dos respuestas cuyos cuerpos se trataron de forma distinta registraban listas de cabeceras idénticas byte a byte, así que quien leía el artefacto no podía saber por qué faltaba un cuerpo.

    #647 (incidencia en GitHub)
  • CambiadoFuncionaMueve las entradas del changelog fuera de CHANGELOG.md y a un archivo por cambio bajo…#638

    Mueve las entradas del changelog de CHANGELOG.md a un archivo por cambio dentro de changelog.d/, de modo que un pull request ya no entre en conflicto con todos los demás que se integraron antes (#638). Cada rama añadía su entrada al principio de ## Unreleased, lo que convertía esa única línea en el punto de contención del archivo: nueve resoluciones manuales en ocho pull requests a lo largo de dos sesiones, cada una un nuevo push y una nueva ejecución de CI, y la resolución era siempre «conserva nuestro bloque y luego el suyo». Un conflicto cuya respuesta nunca varía no aporta información, y es una ocasión para perder un párrafo mientras se piensa en otra cosa. La corrección de .gitattributes que proponía la incidencia (CHANGELOG.md merge=union) se midió y se descartó antes: union fusiona línea a línea, así que cuando dos entradas contienen una línea idéntica (basta una línea en blanco dentro de una entrada), conserva una copia e informa de éxito, borrando en silencio la línea de la otra entrada sin conflicto y sin que nadie tenga motivo para revisarlo. Una primera prueba con líneas deliberadamente distintas se fusionó limpiamente y ocultó ese problema. Cambiar un conflicto ruidoso por pérdida silenciosa de datos es estrictamente peor que el conflicto, así que se publicó la solución estructural.

    #638 (incidencia en GitHub)
  • CambiadoFuncionaUn fragmento se nombra según la incidencia que cierra (changelog.d/638.md), la clave#638

    que es única por rama por construcción: un pull request que cierra dos incidencias escribe dos fragmentos, uno por incidencia, y un cambio que no cierra ninguna escribe no-issue-<slug>.md. Un fragmento contiene la entrada tal como debe aparecer en el changelog (uno o más puntos de primer nivel con sus líneas de continuación, sin front matter ni envoltorio), de modo que las entradas en prosa de varios párrafos que este archivo conserva pasan de ida y vuelta byte a byte en lugar de reformatearse en líneas sueltas. python scripts/build_changelog.py los integra en ## Unreleased en el momento de la publicación, ordenados por número de incidencia y no por el orden que devuelva el sistema de archivos, y --prune elimina los fragmentos que integró. El ensamblado reemplaza toda la región comprendida entre dos comentarios marcadores en lugar de insertar en ella, así que ejecutarlo dos veces produce el mismo archivo en ambas ocasiones, tanto si los fragmentos se eliminaron entre medias como si no. CHANGELOG.md en sí no se regenera en cada pull request, deliberadamente: una puerta que lo mantuviera sincronizado continuamente volvería a poner ambas ramas en el mismo archivo y reconstruiría el conflicto que esto elimina.

    #638 (incidencia en GitHub)
  • CambiadoFuncionaLas puertas de documentación que leían CHANGELOG.md eran el riesgo, porque una puerta#638

    que deja de comprobar en silencio es peor que los conflictos…

    Las puertas de documentación que leían CHANGELOG.md eran el riesgo, porque una puerta que deja de comprobar algo en silencio es peor que los conflictos. Ambas se encontraron y ahora cubren los fragmentos: tests/test_docs_drift.py tenía CHANGELOG.md en PUBLIC_MARKDOWN, así que la puerta solo en inglés, la de «referencias solo a comandos existentes» y la de recuentos obsoletos también leen ahora changelog.d/*.md, y las dos puertas de deriva de recuentos omiten un fragmento por la misma razón que omiten el changelog: una entrada registra lo que era cierto cuando se escribió. tests/test_doc_counts.py excluye deliberadamente el changelog de su escaneo de recuentos en vivo, y su lista de archivos nunca llega a changelog.d/, que es la misma respuesta por el mismo motivo; tests/test_doc_commands.py, tests/test_docs_commands_execute.py y tests/test_examples_gate.py nunca leen el changelog. Un nuevo tests/test_changelog_fragments.py fija cada una de esas respuestas, junto con el nombrado de fragmentos, el orden determinista, el ensamblado idempotente y el hecho de que dos ramas concurrentes simuladas que añaden cada una un fragmento se fusionan sin conflicto.

    #638 (incidencia en GitHub)

Antes (sin fecha registrada)

23 añadido30 cambiado17 corregido
  • CorregidoFuncionaSigue identificando una página cuyo sitio envía una cabecera Set-Cookie sin valor

    (#651).

    Una cabecera sin ningún par name=value (Set-Cookie: Secure; HttpOnly, que emall.by envía junto a dos cookies bien formadas) se convierte en Cookie(name='Secure', value=None) en el jar, y httpx.Cookies.__getitem__ lanza KeyError para ella. Por eso dict(resp.cookies) fallaba con un nombre que el propio iterador del mapeo había producido: tech-detect terminaba con código 1 y un simple error: 'Secure' sin JSON en stdout, para una página que se había descargado con éxito; el MCP seo_tech_detect propagaba el KeyError a quien lo llamaba, y site-audit volvía en silencio sin su sección de tecnologías. Ahora detect_tech recorre el jar de cookies. Un nombre sin valor se conserva con valor vacío en lugar de descartarlo, porque varias huellas (BITRIX_SM_GUEST_ID, craft_session, wfvt_) coinciden solo por el nombre de la cookie, y descartar la entrada perdería esa señal; pero nunca se normaliza en silencio como una cookie corriente: los nombres se informan en malformed_cookies y se citan en un hallazgo, de modo que una cabecera que el sitio envió rota sigue siendo un hecho sobre el sitio. Una respuesta con solo cookies bien formadas no cambia y devuelve una lista vacía.

  • CambiadoFuncionarender-check vuelve a medir sitios comprimidos en lugar de darlos por rotos (#650).

    La ruta de renderizado fijada leía el origen con el stream sin decodificar de httpx y entregaba esos bytes a Playwright junto con el content-encoding del origen. route.fulfill nunca aplica una codificación de contenido al cuerpo que recibe, así que Chromium interpretaba gzip como text/html y construía un DOM a partir del flujo comprimido: sin título, sin h1, sin canonical, sin enlaces, y un tamaño renderizado igual a la transferencia. Cada sitio que comprime su HTML (casi todos) salía como ok: false, reason: incomplete_render, y el mensaje culpaba al renderizado y sugería --wait domcontentloaded o un --timeout más largo, aunque el renderizado había terminado perfectamente. seohead.tech informaba 22 435 bytes renderizados frente a 121 793 brutos; ahora informa 123 048 con el título real y 31 enlaces. La ruta lee ahora la entidad decodificada, elimina content-encoding de lo que reenvía (content-length ya se eliminaba como hop-by-hop, así que Playwright declara la longitud del cuerpo que realmente recibió) y pide al origen solo las codificaciones que este cliente sabe decodificar, en lugar de reenviar la invitación de Chromium a br y zstd. Si una codificación llega sin decodificar de todos modos, la solicitud se aborta y nombra esa codificación, porque dejarla pasar reproduciría el error en silencio. El límite de bytes cuenta ahora bytes decodificados, que es el cuerpo que ve el renderizador: antes, una bomba de compresión pasaba el límite comprimida.

  • CambiadoFuncionaLee Open Graph de un rastreo nativo por la clave que el parser realmente escribe (#646).

    parse_html guarda cada etiqueta bajo su nombre completo de propiedad ({"og:title": ...}, como dice su propio docstring), y crawl/collect.py pedía al mismo diccionario "title", "description" e "image". dict.get devolvía None siempre, así que og_title, og_description y og_image quedaban vacíos en cada página de cada rastreo nativo que se había ejecutado: 0 de 40 920 páginas tenían alguno en la ejecución donde apareció el problema, en un sitio cuyas páginas sí publican Open Graph. Es la regla central del repositorio invertida: un campo no medido leído como medido, y el error se propagó, porque crawl/evidence.py proyecta esas columnas en OG:Title, OG:Description y OG:Image del marco Internal:All, así que una comprobación veía vacío en un rastreo nativo y el valor real en una exportación de Screaming Frog del mismo sitio. La honestidad de check_og ocultó el daño en lugar de mostrarlo: como ninguna columna OG se rellenaba en ningún sitio, la comprobación se omitía, así que un sitio con Open Graph se auditaba igual que uno sin él. El parser no cambia; solo se movió el lado de lectura. Un nuevo tests/test_open_graph_seam.py rastrea dos sitios de prueba en loopback y sigue el valor desde el parser hasta pages.jsonl, luego a la tabla pages del artefacto de escaneo y después a las columnas del marco OG:*; rastrea un segundo sitio sin Open Graph para distinguir «vacío porque no existe» de «vacío porque no se leyó», y fija en el mismo archivo la forma de clave del parser. El fallo era que dos módulos correctos no coincidían en el nombre de una clave, sin ninguna prueba que abarcara a ambos.

  • CambiadoFuncionaResponde a «¿está bien enlazado este sitio y dónde está mal enlazado?», tomando el

    registro de 157 a 161 comprobaciones y añadiendo una skill internal-linking (#634). Las piezas existían (cada enlace con su posición, ancla y marca nofollow en la tabla links, ORPHAN_PAGE, INLINK_BOILERPLATE_ONLY, LOW_LINK_SCORE), y nada las convertía en una respuesta sobre el grafo. Una auditoría de 40 920 páginas llevaba durante horas el titular equivocado por esa razón: el 66 % del sitemap se informaba como inalcanzable por enlaces internos, una cifra que resultaba de restar el número de URL de un rastreo al del sitemap, lo que mide «el rastreador no llegó hasta allí». Recorrer los 5 252 235 enlaces del propio artefacto desde la página de inicio situaba la alcanzabilidad en el 91,9 %. El defecto real era la profundidad: 23 742 páginas (el 58 % del sitio) estaban a más de diez clics de la página de inicio, y la más profunda estaba a 3 005, porque el archivo es una lista enlazada de enlaces «siguiente entrada» en lugar de un árbol. La profundidad de clic es ahora el titular que imprime la auditoría. summary.internal_linking contiene el histograma, el máximo, la división alcanzable/inalcanzable, los enlaces internos por posición en la página y cuántos enlaces repiten otro, y audit.md lo muestra junto al resumen de salud. El recorrido empieza en la URL desde la que realmente arrancó el rastreo, nunca en pages.crawl_depth: esa columna registra dónde llegó el rastreador a una URL por casualidad, y un rastreo sembrado desde el sitemap registra 0 en la mayor parte del sitio, así que un recorrido sembrado desde ella describiría otro lugar. Si no se registró ninguna URL de inicio y más de una página reclama profundidad 0, la medición se niega a ejecutarse y dice cuál.

  • CambiadoFuncionaCuatro comprobaciones leen esos números.

    DEEP_CLICK_DEPTH se dispara en una página indexable cuya ruta más corta desde la URL de inicio supera thresholds.click_depth_max (por defecto 10, y cada hallazgo nombra el número que usó). DUPLICATE_INTERNAL_LINK se dispara en una página que escribe el mismo destino y ancla más de una vez: en el sitio anterior, 509 744 de 1 134 307 enlaces (el 44,9 %) eran repeticiones, y se trataba de una misma cabecera de sitio emitida dos veces, con la segunda copia eliminada por JavaScript, un defecto de plantilla que había requerido un script escrito a mano para encontrarlo. LINK_INSIDE_HEADING y IMAGE_LINK_WITHOUT_TEXT necesitan lo que la región de página de un enlace no puede contener (la cadena de ancestros del propio ancla y su contenido), así que un rastreo nativo registra ahora un link_placement_json pequeño y acotado por página junto al esquema de encabezados, y ambas comprobaciones se omiten por nombre en una exportación de Screaming Frog en lugar de pasar limpias sobre nada.

  • CambiadoFuncionaLas reglas de honestidad que el resto del analizador mantiene se aplican en todo el

    conjunto.

    Un enlace sin posición registrada se cuenta como unclassified y nunca se suma a content: link_position.classify viene desactivado por defecto, lo que deja esa marca en cada enlace, y una ejecución en ese estado debe leerse como «nadie lo revisó» y no como un sitio cuyos enlaces son todos texto de cuerpo. Una posición ausente de la distribución se informa como «ningún enlace clasificado aquí», no como una región que el sitio no tiene: las reglas se prueban en orden y un menú dentro de <header> coincide primero con nav. Un rastreo parcial retira el veredicto de profundidad de clic, se haya disparado o no, porque una frontera nunca descargada puede contener la ruta más corta, y una comprobación que no encuentra nada en silencio se leería como «todas las páginas están dentro del umbral».

  • CorregidoFuncionaDeja de informar como limpia una comprobación condicionada por requisito que nunca se

    evaluó (#635).

    H2_MISSING solo se dispara cuando una configuración establece requirements.require_h2, y el valor por defecto es false, así que en una ejecución normal su rama es inalcanzable. Eso no dejaba rastro: la cobertura lo contaba entre las comprobaciones silenciosas (el cubo que significa «se ejecutó sobre todas las páginas y no encontró nada»), y al lector se le decía que el sitio había superado una comprobación que nadie ejecutó. En la auditoría que lo sacó a la luz, el 61 % de las páginas del sitio no tenía ningún H2 y 5 066 de ellas superaban las 800 palabras, así que la comprobación se habría disparado miles de veces. Ahora se declara omitida por nombre, con un motivo que nombra el ajuste que la desactivó, de modo que la respuesta es «no evaluada, y así se evalúa» en lugar de silencio. require_canonical tiene la misma forma y recibe el mismo tratamiento; su valor por defecto es true, así que todavía no producía una lectura errónea, y ahora no puede empezar a hacerlo.

  • CorregidoFuncionaCorrige el encabezado del backlog de tareas que mostraba «Audit Tasks — None» en

    cualquier auditoría cuya ejecución…

    render_tasks_md construía el encabezado con src.get("project", "site"), pero "project" siempre es una clave presente en el bloque source del backlog: se fija en el momento de la construcción desde run.get("project"), así que una ejecución sin proyecto guarda el valor None ahí en lugar de dejar la clave ausente, y el valor por defecto de dict.get solo se aplica a una clave que falta, nunca a una que contiene None. Un rastreo nativo y un reanálisis dejan project sin definir, así que cada backlog construido a partir de cualquiera de ellos recibía como encabezado la palabra literal «None». Ahora el encabezado usa or, que sí captura un None almacenado, y recurre a start_url o a source del sitio antes de rendirse: el mismo orden que seohead.reports.facts.crawl_domain ya usaba para resolver el nombre de un sitio a partir de su bloque run, ahora exportado y reutilizado aquí en lugar de reinventado, de modo que un backlog construido desde una auditoría sin proyecto nombra el sitio real en lugar de la palabra «site». seohead.reports._normalize_sf_audit tenía la misma forma latente una línea más arriba (run.get("project") or "", en reports/__init__.py): ya estaba protegido contra un None almacenado, pero su alternativa era un dominio vacío en lugar de la URL que la ejecución también conoce, así que el encabezado «SEO Audit: » de los formatos docx y md quedaba en blanco en las mismas situaciones. Ahora recurre a la misma resolución de crawl_domain, en lugar de quedarse vacío.

  • CambiadoFuncionaLee el esquema de encabezados como secuencia y como mapa de la página, tomando el

    registro de 155 a 157 comprobaciones (#632).

    Las ocho comprobaciones de encabezados existentes juzgan los encabezados como conjunto: pueden afirmar que una página tiene un H1 y cuatro H2, y nada más. Así, una página cuyo orden en el DOM es H2, H2, ..., H1, H2 cumplía todas, y también una página cuyos H2 eran todos etiquetas de menú en su cabecera (encontrada en un sitio real como una plantilla de artículo con dieciocho encabezados antes de su propio H1). Lo que faltaba era la evidencia, no la regla: pages guardaba h1, h1_2 y h2, tres cadenas sin orden ni lugar. Un rastreo nativo registra ahora el esquema completo h1-h6 en orden DOM, cada encabezado con su nivel, texto y región de página, en una nueva columna anulable heading_outline_json, y HEADING_BEFORE_H1 y HEADING_IN_PAGE_CHROME lo leen. La región reutiliza la taxonomía que ya usa la clasificación de enlaces (nav, header, sidebar, footer, content, other), de modo que «en la cabecera» significa lo mismo para un encabezado que para un enlace. Un encabezado que ninguna regla de posición reconoce se sitúa frente al área de contenido solo cuando el documento nombra una: un <main>, un [role=main], un <article> o un selector configurado. Cuando la raíz de contenido recurre a todo el <body>, llamar «contenido» a un encabezado significaría solo «en algún lugar de la página», así que la región se registra como no medida y la página aparece entre las comprobaciones omitidas de la ejecución con ese motivo, en lugar de pasar como limpia o marcarse como defecto. El orden no necesita región, así que HEADING_BEFORE_H1 sigue respondiendo para esas páginas. Una exportación de Screaming Frog no trae ningún esquema, y ambas comprobaciones se omiten allí por nombre.

  • CorregidoFuncionaConserva una recopilación terminada cuando la auditoría que la sigue falla (#627).

    Un rastreo nativo de un sitio en vivo pasó veinte minutos recopilando 600 páginas en un artefacto --scan-out y luego imprimió error: 'rel_next_2' (el str() de un KeyError es solo la clave y nada más). Sin fase, sin traceback y sin indicio de que cada página recopilada estaba completa y se podía reanalizar en el archivo. La recopilación confirma sus filas y se cierra antes de que empiece la auditoría, así que cualquier excepción posterior a ese punto es un fallo del analizador y nunca del rastreo. Ahora una excepción inesperada en esa fase se nombra por fase, incluye el tipo de la excepción además de su mensaje y señala el artefacto conservado y el comando que lo reanaliza, igual que ya hacía la ruta de auditoría demasiado grande. La ejecución informa audit_available: false con ese motivo en lugar de terminar por la excepción, y crawl-site sale con código 2 en ese caso: la misma tercera respuesta que ya usa la contradicción del log-scan, porque 0 se leería como «la auditoría se ejecutó y encontró esto» y 1 como «el comando no produjo nada», y ninguna de las dos cosas es cierta para un rastreo cuya evidencia sobrevivió. El KeyError en sí no se reprodujo: el mismo comando contra el mismo sitio en la rama principal actual se completó, así que esto cambia qué ocurre cuando falla una auditoría, no lo que causó este fallo concreto.

  • CorregidoFuncionaDeja de perder la auditoría de un rastreo completado por un presupuesto fijo de

    inspección de 30 segundos al reabrirlo (#631).

    NativeScan.open() lee la cabecera de un escaneo nativo a través de inspect(), que además ejecuta PRAGMA quick_check y PRAGMA foreign_key_check sobre toda la base de datos: una comprobación de seguridad real, pero cuyo coste crece con el artefacto mientras el presupuesto no. Un rastreo de 3,5 horas y 40 920 páginas terminó de recopilar todo lo que se propuso y luego no produjo ninguna auditoría, porque reabrir el artefacto resultante de 1 GB necesitaba unos 48 segundos de validación frente a un presupuesto fijado en 30. Peor aún, el fallo no daba ninguna pista de que el problema era el presupuesto: el aborto por tiempo llega desde SQLite como un simple sqlite3.OperationalError("interrupted"), que se envolvía tal cual en cannot inspect native scan: interrupted, indistinguible de un archivo realmente corrupto. Se corrigen las dos cosas. El presupuesto por defecto se deriva ahora del tamaño del artefacto (un mínimo de 30 segundos para archivos pequeños, más una holgada asignación por byte, bastante por debajo de la velocidad de validación medida de unos 22 MB/s, porque esto es un techo frente a una lectura colgada y no un objetivo de rendimiento); un timeout_seconds explícito de quien llama sigue prevaleciendo. Y un aborto por tiempo lanza ahora un ScanError que nombra el presupuesto, el tiempo transcurrido y el tamaño del artefacto, de modo que quien opera puede distinguir un archivo grande y lento de uno corrupto, en lugar de leer «interrupted» como un error suyo.

  • AñadidoFuncionaAñade crawl-site --resume <scan.sqlite> (#619).

    NativeScan.resume_snapshot(), la tabla resume_state y el escritor que la rellena existían desde que se diseñó el artefacto de escaneo, y crawl_to_scan ya continuaba un archivo existente, pero solo para quien llamaba reproduciendo byte a byte los ajustes efectivos originales, y ninguna interfaz lo ofrecía. Apuntar --scan-out a un artefacto interrumpido con cualquier flag cambiado se rechazaba como desajuste de configuración, así que en la práctica un rastreo interrumpido (6 516 de 34 635 páginas, sobre el sitio de otra persona) tenía que empezar desde cero. --resume recibe solo el artefacto y nada más: la URL de inicio y la configuración efectiva completa se leen del archivo, porque son aquello con lo que se construyó la frontera almacenada, y cualquier otro flag que module el rastreo y se pase junto con él se rechaza en lugar de aplicarse. Un escaneo escrito por otra versión del programa, registrado para otra URL de inicio, ya terminado, derivado de un reanálisis o rastreado con cabeceras de credencial que solo puede almacenar redactadas se rechaza por nombre a partir del propio archivo, antes de despachar una sola solicitud. crawl-site imprime ahora también al salir una línea en stderr que indica si el rastreo terminó o se detuvo antes, por qué, y cómo continuarlo; salvo tras un presupuesto de URL o de duración, que un reanudado también lee y por tanto no puede pasar, caso en que la línea lo dice en lugar de ofrecer una operación sin efecto. run.crawl_resumed sigue siendo el registro duradero: un rastreo reanudado del sitio de prueba sin conexión descarga cada URL exactamente una vez entre ambos procesos y produce una auditoría idéntica a la de un rastreo sin interrupciones en todos los campos salvo ese.

  • CorregidoFuncionaDeja de dar por limpia una página sin renderizar en render-check, y deja de descartar

    la evidencia del HTML bruto con un renderizado fallido (#642). Dos consecuencias de la guarda de #623, ambas en render.py. Primera: una renderización que agotó el tiempo en su hito de carga recurre a leer el DOM en domcontentloaded, lo que es sólido en sí mismo, pero cuando ningún script se había ejecutado para entonces, el DOM renderizado era igual al HTML bruto, el comparador no encontraba nada y la ejecución informaba ok: True, js_dependent: False y el único hallazgo «Raw HTML and rendered DOM are materially equivalent; JavaScript rendering does not determine SEO-visible content», con gravedad de aviso, sobre una página que nadie había renderizado. wait_reached registraba la verdad, pero la auditoría de sitio solo transporta al informe el texto de los hallazgos, así que la verdad nunca llegaba. Ahora una ejecución que recurrió a un hito anterior lo dice en la propia lista de hallazgos, retiene la confirmación de que todo está bien y devuelve js_dependent: None (esta ejecución no lo sabe) en lugar de False. Esto ocurría con el valor por defecto --wait load, no solo con networkidle pedido de forma explícita. Segunda: la guarda devolvía su única declaración «la comparación no está disponible» antes de llegar a la rama de cáscara vacía, y el retorno temprano de render_check omitía por completo la clave empty_shell. Así, un punto de montaje vacío de una aplicación de página única, que detect_empty_shell() lee de la respuesta bruta del servidor y que no necesita navegador alguno, se descartaba junto con la renderización fallida. Como la cáscara de una SPA es justamente la página cuya renderización agota el tiempo, el hallazgo se perdía precisamente donde más importaba. Un hallazgo derivado de la mitad bruta sobrevive ahora a una renderización no terminada; solo se suprimen los hallazgos derivados de la mitad renderizada. En un rastreo, una sonda de renderizado que no llegó a ningún veredicto pasa ahora a patterns_unprobed con su motivo (el canal de #626), en lugar de contar como un patrón medido y considerado sin necesidad de renderizado.

  • CambiadoFuncionaInforma de un robots.txt ilegible como un hecho sobre el sitio, no como error interno

    (#629).

    EMPTY_ROBOTS (el sustituto que _fetch_robots devuelve en cada ruta donde no se pudo leer robots.txt) seguía con la forma de robots ya parseado de antes de que el parser incorporara grupos y sitemaps. La ruta de éxito devuelve la forma de parse_robots, y es la única forma que acepta el contexto robots_summary del artefacto de escaneo, así que en modo --scan-out un rastreo se abortaba con native parsed robots summary is invalid siempre que robots.txt era inalcanzable, respondía 429 o 5xx, redirigía fuera del host, entraba en un bucle, superaba el límite de saltos o devolvía un cuerpo que no era text/plain. También abortaba si era un 404 simple, que no es un error sino el caso RFC 9309 de «sin restricciones» y el más frecuente de los siete. Así se perdían ambos resultados documentados tras una sola línea: un robots.txt ausente ahora permite rastrear sin restricciones de nuevo, y uno no disponible detiene la ejecución con una nota que indica cuál de las seis formas de fallo se produjo. El modo de rastreo en directorio heredado nunca lo notó, porque nada lee las claves antiguas. Lo encontramos en un sitio real cuyo robots.txt redirige con 302 a un endpoint de sincronización de cookies para cualquier user agent que no reconozca.

  • CorregidoFuncionaCorrige que escalate() cuente una sonda de renderizado fallida como «este patrón no

    necesita renderizado» (#626). Para cada patrón de plantilla, toma una URL de muestra y decide si ese patrón necesita una descarga más completa con JavaScript renderizado, pero cuando todas las muestras de un patrón fallaban al sondear (un fallo al lanzar el navegador, un agotamiento de tiempo o un renderizado incompleto, los modos de fallo habituales de un rastreo real), el for/else seguía registrando el patrón como sondeado, y acababa ni escalado ni en la lista de patrones que la ejecución no pudo evaluar. Eso invertía la regla central del proyecto: la evidencia ausente o no medida nunca debe leerse como limpia. Un patrón del que no se había aprendido nada se rastreaba como estático en silencio y se informaba igual que uno medido de verdad y considerado sin necesidad de renderizado. EscalationResult informa ahora de ese patrón en patterns_unprobed, junto a los patrones cortados por plazo que ya se seguían allí, y registra el motivo del fallo de la sonda en el nuevo patterns_unprobed_reasons, de modo que un informe pueda decir «este patrón no fue evaluado» en lugar de dar a entender que sí. Un patrón con al menos una sonda exitosa no cambia: esto solo altera lo que ocurre cuando todas las sondas de un patrón devuelven ok: False.

  • CorregidoFuncionaDeja de informar de un renderizado sin terminar como defecto del sitio en render-check

    (#623).

    Cuando la renderización no se completó, la instantánea renderizada llegaba sin título, sin h1, sin canonical, con cero enlaces y una quinta parte de los bytes de la respuesta bruta, y el comparador leía esa vacuidad como evidencia sobre el sitio: emitía «el título cambia después de JavaScript» sobre un título que la renderización nunca leyó, y «el canonical lo inyecta JavaScript» sobre un canonical que nunca vio. En una auditoría real eso fueron cuatro falsos hallazgos seguidos, cada uno del tipo que lleva a un desarrollador a buscar un error de JavaScript que no existe. Ahora el par se evalúa antes de compararlo: cuando la respuesta bruta contiene puntos de referencia y el documento renderizado no contiene ninguno de ellos, con un tamaño que es solo una fracción del bruto, la comprobación devuelve ok: false con reason: "incomplete_render", un motivo con nombre que incluye ambos recuentos de bytes, y ambas instantáneas para inspección: sin hallazgos y con js_dependent: null en lugar de false, porque la ejecución no lo sabe. site-audit lo registra en summary.tools_failed, donde debe ir una comprobación no medida. La detección es deliberadamente estrecha: un solo punto de referencia que sobreviva, o un documento renderizado de al menos la mitad del tamaño de la respuesta bruta, se compara como antes, y una página sin título y sin enlaces en ninguno de los dos lados se mide y simplemente está vacía, no se da por no medida. Un título que un script reescribe de verdad sigue disparando su hallazgo. La estrategia de espera también ayuda con la causa habitual: un sitio cuyos scripts de analítica, chat o publicidad con sondeo largo nunca alcanzan el estado de red inactiva agotaba el tiempo de toda la comprobación bajo --wait networkidle; ahora recurre a leer el DOM en domcontentloaded sin una segunda navegación, con wait_reached registrando de qué hito procede realmente la instantánea, más una pausa breve para los scripts diferidos. Una página cuyo DOMContentLoaded nunca se disparó sigue siendo un fallo de renderizado, no uno incompleto.

  • CambiadoFuncionaDa a crawl-site una línea de progreso en vivo (#619, mitad de progreso).

    Un rastreo nativo imprimía su tasa de solicitudes efectiva y después no mostraba nada hasta terminar; en un sitio de 34 000 páginas, la única forma de saber que seguía trabajando era mirar cómo crecía el archivo de escaneo con ls -la. Ahora la línea se actualiza en su lugar en una TTY, con las páginas descargadas, las URL conocidas hasta el momento, su porcentaje respecto a ese conjunto, la tasa actual de solicitudes en una ventana móvil, el tiempo transcurrido y el tamaño del artefacto de escaneo cuando --scan-out lo está escribiendo. Lo que deliberadamente no hace es sugerir un total que no puede conocer: un rastreador descubre su propia carga de trabajo, así que el denominador es fetched + queued limitado por el presupuesto de URL, se etiqueta como known y no como total, y una línea de cabecera impresa una sola vez indica que la frontera sigue creciendo y que el porcentaje no es una estimación de cuándo terminará la ejecución. Una tasa no medible se muestra como rate n/a, nunca como 0.0 req/s. Ambos números vienen de las propias estructuras del rastreo (en un escaneo SQLite, de la misma consulta resume_snapshot por la que se guía el bucle de recopilación), de modo que lo que se ve en pantalla es lo que el artefacto contiene en ese instante y no un recuento paralelo que pueda desviarse. Una salida no TTY (una tubería, un archivo de registro, CI) recibe una línea sencilla cada 30 segundos en lugar de redibujos con retorno de carro, y un nuevo -q/--quiet silencia tanto la línea de progreso como la línea inicial de tasa, dejando intacto el resultado JSON en stdout.

  • CambiadoFuncionaCierra las tres filas de paginación que #385 dejó abiertas, y lleva el registro de 152 a

    155 comprobaciones…

    PAGINATION_MULTIPLE y PAGINATION_URL_NOT_IN_ANCHOR informan de una página que declara dos sucesores distintos, o cuya URL declarada no aparece también como ancla en la misma página. Los sucesores se comparan tras normalizar la URL, la misma identidad que usa la mitad de ancla, de modo que /blog/page/2 y /blog/page/2/ procedentes de dos plugins son un único sucesor escrito de dos formas, no una serie ambigua. PAGINATION_URL_NOT_IN_ANCHOR necesita el inventario completo de enlaces de una página y lee para ello la exportación All Inlinks. PAGINATION_MULTIPLE no lo necesita y ahora lee primero las columnas de ocurrencia, más ligeras, Internal:All con rel="next" 2 / rel="prev" 2, del mismo modo que CANONICAL_MULTIPLE ya responde a partir de Canonical Link Element 2; All Inlinks solo es una alternativa para un perfil cuyo Internal:All se escribió sin esas columnas. PAGINATION_SEQUENCE_ERROR informa de una ruptura en una secuencia de números de página que la serie sigue en otro caso, según la propia advertencia de la incidencia: una serie puede empezar en un número distinto de uno, un salto regular no es una ruptura, y una serie cuyas URL no indican número de página se declara no evaluada en lugar de juzgarla contra una numeración que habría que inventar. Cada serie que queda sin juzgar se nombra entre las comprobaciones omitidas de la ejecución, con el motivo que es cierto para *esa* serie: un salto regular, un ciclo, una serie demasiado corta para contener una secuencia y un número de página ilegible son cuatro afirmaciones distintas, y tres de ellas describen series cuyas URL indican todas su número. El recuento es por serie, no por ejecución, de modo que la forma habitual de WordPress (la página uno en /blog/ sin número y el resto en /blog/page/N/) no puede desaparecer tras una única serie juzgable en otro punto del mismo rastreo.

  • AñadidoFuncionaAñade una puerta de cobertura de veredictos (#98): test_check_producer_gate.py demostró

    que cada…

    Añade una puerta de cobertura de veredictos (#98): test_check_producer_gate.py demostraba que cada ID de comprobación está registrado y que cada función check_* se despacha, pero no decía nada sobre si la conclusión de una comprobación se había probado alguna vez como verdadera frente a un marcado que de verdad tiene el defecto, ni sobre si se mantiene en silencio ante un marcado que no lo tiene. Esa es exactamente la brecha que dejó pasar #94, #95 y #96 a través de todas las pruebas existentes mientras seguían disparándose mal en sitios reales. test_check_verdict_coverage.py recorre tests/ de forma estructural (AST, no una lista fija de llamadas) buscando las dos mitades por comprobación, y hace fallar la compilación para cualquier comprobación recién añadida al registro sin una prueba en ambos sentidos ni una exención con nombre y motivo. De las 152 comprobaciones del registro, 88 ya tenían prueba en ambos sentidos; un nuevo test_check_verdict_gaps.py cierra otras 22 de las brechas baratas de probar que detectó el escaneo (longitud y duplicación de title y description, duplicación de H1, presencia de H2, higiene de URL, comprobaciones de directivas y marcado, códigos de respuesta, y las dos comprobaciones de exportación con filtro nativo). Las 64 restantes quedan nombradas, no ocultas, en el ratchet KNOWN_UNCOVERED de la puerta: hay que reducir esa lista a medida que llega la cobertura, y nunca debe crecer para admitir una comprobación añadida después de que existiera esta puerta.

  • CorregidoFuncionaCorrige un defecto en la selección de grupos de robots.txt que permitía que un valor

    User-agent vacío anulara la política por defecto de un sitio (#566). Una línea User-agent: vacía, o una cuyo nombre de bot se tragaba un comentario en línea (User-agent: # old bot rule), se parseaba como un token vacío. _rules_for trataba ese token como cualquier otro nombre literal: es un prefijo de longitud cero de todos los agentes, así que coincidía con todos, y como contaba como coincidencia *con nombre*, superaba al grupo real User-agent: * del archivo para cada rastreador que el archivo no menciona. Un robots.txt cuya única regla sustantiva era User-agent: * / Disallow: / figuraba, por tanto, como totalmente rastreable, tanto en el informe de acceso de bots de IA como en el propio control de descargas del rastreador en vivo, que llama al mismo is_allowed. Ahora los tokens vacíos se omiten, de modo que un grupo así no nombra a nadie y se aplica el grupo comodín; el grupo con nombre más específico sigue ganando, y un robots.txt que no nombra a nadie sigue significando que todo está permitido.

  • CorregidoFuncionaCorrige cuatro defectos de selección de exportaciones y validación de ejecuciones que

    permitían a una auditoría presentar un resultado que no podía sostener…

    El matcher de internal_all solo exigía el token de nombre de archivo internal, así que una pestaña Internal parcial por tipo (por ejemplo internal_html.csv, sin ninguna fila que no fuera HTML) satisfacía la exportación maestra obligatoria Internal:All sin ninguna advertencia de maestro ausente; ahora también exige all. discover_exports elegía el primer candidato para una clave lógica en orden alfabético cuando dos archivos coincidían con ella (por ejemplo, internal_all.csv e internal-all.csv presentes a la vez con filas distintas), descartando en silencio el otro sin que nada en los metadatos de la ejecución indicara que hubo una elección; ahora lanza un error que nombra a todos los candidatos. run_sf escogía la subcarpeta con marca de tiempo más reciente bajo --out sin importar cuándo se creó, así que una re-ejecución que terminaba con código 0 sin escribir nada (un fallo de arranque que Screaming Frog no informa como salida distinta de cero) podía devolver las exportaciones de una invocación anterior como si fueran frescas; ahora compara con una instantánea tomada antes de que arranque el proceso y falla de forma ruidosa cuando no aparece nada nuevo. build_command añadía --auth-config solo cuando el archivo de perfil indicado ya existía, con lo que un rastreo arrancaba en silencio sin autenticación ante una ruta mal escrita o borrada; eso es apropiado para el perfil opcional por defecto seospiderconfig, pero incorrecto para un perfil que la persona que llama pidió de forma explícita. Ahora, un sf_cli.auth_config explícito que falta lanza un error antes de que arranque Screaming Frog.

  • CorregidoFuncionaCorrige dos defectos de extracción de contenido en seohead/checks/parser.py (#138,

    #140).

    collapse_whitespace volvía a decodificar entidades HTML sobre la decodificación única que el parser lxml de BeautifulSoup ya hace en cada valor de tag.get_text()/tag.get(attr) que entrega a ese helper: un no-op silencioso en el marcado corriente, pero en una página cuyo CMS o pipeline de importación ya había escapado dos veces sus entidades (un artefacto real y frecuente) convertía una sopa de entidades visiblemente rota en texto de aspecto limpio y acortaba la longitud informada por debajo de lo que de verdad muestra una pestaña del navegador o un snippet de SERP, invirtiendo en ambos sentidos las comprobaciones de longitud de title y description. El helper ya no decodifica nada. Por otro lado, la extracción de enlaces y de URL de origen recorría todo el documento sin condiciones, así que un <a>/<img> que existía solo dentro de un <template> inerte (nunca parte del documento renderizado según la especificación HTML, y nunca solicitado por un navegador ni por un rastreador salvo que un script lo clone) se informaba como enlace real de la página y spider.py lo descargaba de verdad: el mismo fallo de URL fantasma que se cerró para <base href> en #4. Ambos extractores ahora omiten los descendientes de <template>. <noscript> se deja deliberadamente accesible ahí, a diferencia de la extracción de texto: es marcado de respaldo real y definido por la especificación, que un cliente con JavaScript desactivado (y la pasada de rastreo sin renderizado de los buscadores) sí carga, y excluirlo ocultaría al auditor una URL que de verdad se puede descargar. El recuento de palabras tampoco cuenta ahora el texto de los descendientes de <svg>/<math> (el <title> de accesibilidad de un sprite de iconos, el <text> de un glifo, la notación MathML) como contenido del cuerpo: una cabecera con 20 iconos podía duplicar el recuento de palabras de una página frente a su contenido real. Esa lista de exclusión vive ahora en un solo lugar, content_area.TEXT_EXCLUDED_TAGS, compartida por ambos extractores de texto en lugar de dos copias que ya se habían desincronizado.

  • CorregidoFuncionaConserva los tokens rel completos de un enlace, su atributo target y su href bruto

    (sin resolver), y extrae los elementos <form>: método, action y si hay campo de contraseña (#125). Seis incidencias catalogadas dependían de que se descartaran esos tres datos: enlaces cruzados de origen inseguros (target="_blank" sin rel="noopener"/"noreferrer"), enlaces relativos al protocolo (//host/path, antes de resolver), enlaces salientes a localhost, una página que recibe a la vez un enlace interno seguido y otro nofollow, una action de formulario insegura y un formulario de contraseña servido desde una página HTTP sin cifrar. Las seis son ahora UNSAFE_CROSS_ORIGIN_LINK, PROTOCOL_RELATIVE_LINK, OUTLINK_TO_LOCALHOST, FOLLOW_AND_NOFOLLOW_INLINKS, FORM_URL_INSECURE y FORM_ON_HTTP_URL en el registro. Las comprobaciones de formulario, localhost y mezcla de nofollow solo necesitan campos que cada rastreo ya registraba, así que esas cuatro se ejecutan siempre; el par de enlaces cruzados y de enlaces relativos al protocolo necesita link_attributes.capture, desactivado por defecto, porque los datos extra por enlace subieron alrededor de un +50 % en un rastreo sintético de 3387 páginas con 150 enlaces por página: unos +95 bytes por enlace, +46 MiB en total, de los que raw_href por sí solo representa la mayor parte. El registro pasa de 121 a 127 comprobaciones.

  • CorregidoFuncionaCorrige que report-build renderice en silencio un informe sin hallazgos para un

    análisis de SF Analyzer…

    Corrige que report-build renderice en silencio un informe sin hallazgos para un audit.json de SF Analyzer (#151). La receta documentada (sf run --tasks canalizado a report-build --format docx/xlsx/csv/md) leía las claves findings y las claves planas de página, que el esquema de SF no usa (los hallazgos viven bajo issues y los datos de página bajo pages[].metrics); el desajuste producía un resumen 0/0/0/0 con seguridad para una auditoría que sí encontraba incidencias críticas reales, sin secciones de hallazgos. Ahora build_report reconoce tanto la forma nativa seohead.site-audit/1 como la de SF Analyzer, y normaliza la segunda en el contrato plano que ya entienden los cuatro escritores para personas antes de renderizar. --format json no cambia: ya devolvía correctamente el documento original, y eso demostró que los datos nunca faltaron. Un documento que no coincide con ninguno de los dos contratos se rechaza con ok: False y un nombre del desajuste de esquema, en lugar de renderizarse como un entregable vacío, y se elimina el condicional muerto if ... : pass que parecía una validación pero nunca hacía nada. tests/test_docs_commands_execute.py compara ahora el resumen renderizado de la receta documentada con los totales del propio audit.json, no solo su código de salida.

  • CambiadoFuncionaCierra dos brechas de seguridad de dinero en seohead/data_sources/ (#157, #159).

    geo_guard comprobaba solo la cadena orientativa country, así que search_volume/keyword_ideas/keyword_difficulty/serp podían seguir llegando al endpoint en vivo de DataForSEO con location_code=2643 (Rusia) o 2112 (Bielorrusia) siempre que quien llamaba diera el geo-objetivo numérico sin rellenar también country; ahora la guarda comprueba primero location_code, porque es el campo que realmente se factura. Además, un error a nivel de red (URLError/TimeoutError/SSLError) durante una llamada facturada (el post de DataForSEO, el /set de Arsenkin y wordstat.topRequests/wordstat.dynamics/web.searchAsync de Yandex Cloud) reintentaba la misma carga sin clave de idempotencia y solo registraba el intento que finalmente devolvía una respuesta. Ninguno de los tres proveedores ofrece un mecanismo de idempotencia para esos endpoints, así que ahora una respuesta perdida no se reintenta: el intento se registra en el libro de gasto (coste desconocido, marcado como attempt_failed: network_error) y la llamada falla sin más, en lugar de arriesgar un segundo cargo. Las lecturas idempotentes (/check//get de Arsenkin, el sondeo de operaciones de Yandex Cloud) no cambian y siguen reintentando. yandex_cloud.WebSearch.search_batch aísla un envío perdido en su propia consulta en lugar de abortar el lote. metrika.py reintenta los errores de red de la misma forma, pero no es dinero facturado y no se modificó; queda señalado para un seguimiento si la creación de sus exportaciones de Logs API debe recibir el mismo tratamiento por motivos de cuota.

  • CambiadoFuncionaCierra una brecha de DNS rebinding en http_client() (#142): pinned_target(), la

    corrección de la ventana TOCTOU descrita en #14, protegía solo la descarga en modo lista de collect.py: las otras catorce llamadas, incluido el motor crawl-site de spider.py, dejaban que httpx resolviera el DNS una segunda vez, de forma independiente, para abrir el socket. Así, un resolutor hostil que respondiera a esa segunda consulta de forma distinta a la de la propia guarda podía alcanzar 169.254.169.254 o cualquier dirección RFC 1918, sin importar el veredicto de la guarda. Ahora http_client() construye cada cliente sobre un transporte que fija la conexión a la dirección que resuelve por sí mismo, tanto en la primera solicitud como en cada salto de redirección, conservando el nombre de host solo para la cabecera Host y para el SNI de TLS; así la corrección es estructural y no una disciplina que cada llamador debía recordar. SEOHEAD_ALLOW_PRIVATE_NETWORKS/SEOHEAD_ALLOW_PRIVATE_HOSTS no cambian.

  • CorregidoFuncionaCorrige el contrato de códigos de salida CLI/MCP para un fallo que el propio handler

    notifica, y completa el conjunto de flags de origen…

    Corrige el contrato de códigos de salida CLI/MCP para un fallo que el propio handler notifica, y completa SOURCE_FLAGS (#155, #156). Un handler que devuelve {"ok": false, ...} (la forma documentada de la capa de herramientas para informar de un fallo de descarga, parseo o proveedor sin lanzar excepción) imprimía ese JSON y salía con código 0 en la CLI, y devolvía un resultado normal (no isError) por MCP, así que una canalización que dependía de $? o un cliente que solo comprobaba isError no podían detectarlo. Ahora cli.py sale con código 1 en ese caso (el código 2 de log-scan para una ejecución que se contradice sigue siendo una señal aparte y documentada, véase docs/USAGE.md), y mcp_server.py lanza ToolError desde un envoltorio compartido _checked(), de modo que el cliente ve isError. Ambos llaman a una única handlers.handler_failed(), para que las dos interfaces no diverjan sobre qué cuenta como fallo. Por otro lado, a SOURCE_FLAGS se le añadieron --phrase, --keywords, --query/--queries, --seed, --counter y --before/--after: cada uno ya identifica la entrada completa de un comando igual que hace --url, pero faltaban, así que un bucle por línea sobre cualquiera de ellos procesaba en silencio solo su primera línea. El conjunto se construye ahora con _source_flag() en el punto donde se declara cada flag, en lugar de enumerarlo a mano por separado, para que no pueda desincronizarse de nuevo.

  • CambiadoFuncionaAmplía docs/scenarios/ de diez cadenas a cincuenta y seis, agrupadas por la pregunta

    con la que llega quien lee (#120). Qué escenarios existen lo decide el mapa de cobertura y no el gusto: cada uno declara las incidencias catalogadas que resuelve, y tests/test_scenario_coverage.py afirma que cada incidencia que esta herramienta dice encontrar aparece en al menos un escenario, que ningún escenario nombra una incidencia que el mapa no lista y que ninguno omite sus límites. Las 143 incidencias detectables están cubiertas. Cada comando de cada archivo se sigue ejecutando en CI contra el sitio de prueba: la suite ejecuta 2008 pruebas, de las cuales la puerta de comandos de documentación es ahora el grupo más grande.

  • CambiadoFuncionaAfirma los límites del propio protocolo sitemap (#124): SITEMAP_TOO_MANY_URLS por

    encima de 50 000…

    Afirma los límites del propio protocolo sitemap (#124): SITEMAP_TOO_MANY_URLS cuando hay más de 50 000 entradas en un archivo, SITEMAP_TOO_LARGE por encima de 50 MB sin comprimir, y SITEMAP_URL_DUPLICATED para una URL declarada en más de un sitemap, nombrando ambos documentos. Un archivo que supera cualquiera de los límites es inválido, no solo grande: un buscador puede leer una parte y descartar el resto sin que el titular del sitio vea nada, y los umbrales vienen del protocolo, no de la configuración. Ambos parsers registran ahora el tamaño en bytes y el número declarado por documento, y los hallazgos nombran el sitemap hijo en lugar del índice. El registro pasa de 118 a 121 comprobaciones.

  • AñadidoFuncionaAñade docs/GUIDELINE.md, el documento que una persona lee primero (#121): qué es esto y

    qué no es, una primera ejecución de principio a fin, cómo elegir la tasa de rastreo y cómo saber si los errores son tuyos, cómo leer audit.json sin que te induzca a error, qué cambia el archivo de configuración y qué solo cuesta, los seis errores que todo el mundo comete al principio, qué hacer cuando la herramienta se equivoca y qué no puede responder en absoluto. Enlazado en primer lugar desde el README, por delante de la referencia.

  • AñadidoFuncionaAñade docs/COVERAGE_SF_ISSUES.md, generado desde seohead/sf/core/sf_issue_map.py:

    cada una de las 320 incidencias del catálogo publicado del sector, con exactamente un estado (encontrada por una comprobación con nombre, encontrada por un comando con nombre, encontrada en parte con la parte que falta indicada, una brecha con nombre o una decisión con su motivo). (#119) De las 212 incidencias dentro del alcance, 126 se encuentran hoy y 17 en parte; 41 son brechas y 28 necesitan algo que deliberadamente no se construyó. Accesibilidad (92) y AMP (16) se descartan como decisiones únicas, con sus listas completas a la vista para que la decisión sea auditable. Una prueba verifica que cada ID de comprobación y cada comando referenciados siguen existiendo, de modo que un cambio de nombre rompe la compilación en lugar de dejar el documento desactualizado. Sustituye a docs/CHECKLIST_AUDIT.md, que se escribió sin tener el catálogo a mano.

  • CambiadoFuncionaEl sembrador de sitemap solicita la dirección que publicó el sitemap, no su forma

    normalizada (#115). sitemap.crawl() devolvía solo el loc normalizado, así que un sitemap que declaraba /a/ provocaba una descarga de /a: en la mayoría de los CMS, un 301 que el rastreador inventaba y después informaba como hecho sobre el sitio, y un 404 allí donde la forma sin barra final ni siquiera está enrutada. Cada entrada lleva ahora loc tal como se publicó, junto a loc_normalized para los consumidores que comparan por él. Las estadísticas de redirección de rastreos anteriores sembrados desde sitemap son sospechosas por esta razón.

  • CambiadoFuncionaReestructura la skill de operador en un directorio controlador (#111).

    .claude/skills/ tiene ahora dos niveles: 21 skills de método, cada una cubre bien una sola cosa, y control/, que decide cuáles de ellas ejecutar en un sitio que nadie ha revisado todavía. El controlador enruta en lugar de repetir, y contiene cinco sub-skills cargables (alcance, tasa y carga, lectura de una auditoría, verificación y entregables) y un archivo de referencia de tres ficheros (defectos encontrados en sitios reales y qué los delató, qué población describe cada comprobación, y qué no puede responder en absoluto el toolkit). Las comprobaciones de solo inglés y de comandos de documentación cubren ahora cada archivo Markdown bajo un directorio de skill, no solo SKILL.md.

  • AñadidoFuncionaAñade tests/chains/: un sitio de prueba construido con las formas que realmente rompen

    las cadenas —…

    Añade tests/chains/: un sitio de prueba construido con las formas que realmente rompen las cadenas (las dos formas con barra de una misma URL, un cuerpo que no es UTF-8 válido, una página windows-1251, una cabecera de sitio fuera de <main>, un enlace a otro host, una ruta bloqueada por robots), rastreado por loopback, con diecisiete aserciones sobre la ejecución completa y no sobre un módulo concreto (#112). Cuatro propiedades: conservación (un número no cambia de significado al viajar), población (un hallazgo trata sobre un miembro del conjunto que describe), determinismo (dos rastreos, dos niveles de concurrencia, una sola respuesta) y representación (una página indica cómo se midió). Las reglas de población son las propias de logscan, así que una contradicción que el escáner puede nombrar es una prueba de cadena que la afirma.

  • CambiadoFuncionareconcile_sitemap informa de cada URL tal como se escribió, no tal como se normalizó.

    La comparación sigue haciéndose sobre la clave normalizada, pero un hallazgo que nombraba una forma normalizada citaba una URL que no aparecía en ningún lugar del rastreo: inaccionable para quien lee e indistinguible, para el escáner de anomalías, de un hallazgo sobre una página nunca descargada.

  • AñadidoFuncionaAñade docs/scenarios/: diez cadenas de extremo a extremo, cada una con los comandos

    reales en orden, el artefacto que sale, lo que cuesta y lo que esa cadena no puede responder (#110). El resto de la documentación enumera lo que tiene el toolkit; esto describe lo que hace. Enlazado desde el README por encima de la lista de herramientas, de modo que quien evalúa el repositorio encuentra primero las cadenas y después el inventario. Cada comando mostrado se ejecuta contra el sitio de prueba mediante tests/test_docs_commands_execute.py, cuyo extractor y cuyas puertas de solo inglés y de recuento recorren ahora docs/ en todos sus niveles, no solo en el superior.

  • AñadidoFuncionaAñade log-scan (CLI) y seo_log_scan (MCP): lee los propios artefactos de una

    ejecución terminada y…

    Añade log-scan (CLI) y seo_log_scan (MCP): leen los propios artefactos de una ejecución terminada e informan de afirmaciones que no pueden ser ciertas a la vez (#109). Ocho reglas, cada una escrita a partir de un defecto que llegó a producción pasando por toda la suite de pruebas: un tamaño registrado que no coincide con el archivo en disco, una proporción de texto por encima del 100 %, una comprobación que se dispara más veces de las que hay páginas donde disparar, un hallazgo sobre una URL que la ejecución nunca descargó, una canonical tratada como redirección mientras esa URL respondía 2xx en la misma ejecución, un resumen que no coincide con sus propias filas, palabras contadas en una página de cero bytes y páginas medidas de dos formas cuando solo algunas dicen cuál. Cada anomalía nombra ambos valores y de dónde se leyó cada uno. La CLI sale con código 2 cuando una ejecución se contradice, para que una canalización se detenga en lugar de publicar las cifras.

  • CambiadoFuncionaEl test de pacing entre workers ya no mide el reloj de pared (#107).

    _DispatchGate lee ahora el reloj inyectado del rastreo en lugar de llamar directamente a time.monotonic(), así que la prueba lo maneja con un reloj virtual que avanza solo cuando algo duerme: los instantes de despacho son la aritmética propia del rastreador y la aserción es exacta. La forma anterior comparaba intervalos reales transcurridos con un mínimo de 0,024 s y fallaba sin que el código cambiara siempre que la máquina estaba ocupada.

  • CambiadoFuncionaCierra la segunda mitad de la auditoría de ajustes no conectados (#91).

    http.headers se combina en cada solicitud junto a las cabeceras de credencial; speed.adaptive controla el retardo y el ajuste de concurrencia del throttle (los contadores de timeouts y de errores de servidor siguen funcionando, porque dejar de reintentar es un mecanismo aparte de retroceder); discovery.hyperlinks.store / .crawl, discovery.external.store y discovery.redirects.crawl deciden ahora qué registra el rastreo y qué sigue. discovery.canonicals.*, discovery.external.crawl y discovery.redirects.store se eliminan en lugar de conectarlos: nombraban una capacidad que el spider no tiene (seguir canonicals, rastrear entre hosts) o un estado que no puede retener, y un ajuste que aparece en --config-help y en el manifiesto de la ejecución sin cambiar nada es peor que no tener ajuste. La lista de excepciones del canario de cobertura queda ahora vacía: cada ruta de DEFAULTS cambia un resultado observable y un test la nombra.

  • CambiadoFuncionaDetectar el área de contenido a partir de la semántica del propio documento cuando no hay

    nada configurado (#96): primero main, después [role="main"] y luego article, y registrar cuál coincidió como auto_main / auto_role_main / auto_article. El valor anterior por defecto —todo el body menos las etiquetas nav y footer— contaba 126 palabras de plantilla de un total de 433 en una entrada real de WordPress en directo (29 %), incluido un enlace de «saltar al contenido». Esa inflación afectaba en la misma dirección a THIN_CONTENT y LOW_TEXT_RATIO en todas las páginas de una plantilla. header y aside se suman a nav y footer en DEFAULT_EXCLUDE_TAGS para la vía de respaldo. Un selector configurado sigue teniendo prioridad, y si no coincide con nada, se recurre a fallback_default_body en lugar de detectar en silencio otra región.

  • CambiadoFuncionaURL_NOT_IN_SITEMAP ahora compara páginas con páginas (#94).

    Antes comparaba las URL de un sitemap con todos los destinos del grafo de enlaces del rastreo. Así, en un sitio real de 124 páginas se activaba 392 veces: 362 archivos de imagen a los que una galería enlaza directamente, cinco enlaces a otros hosts y 30 URL que el rastreo nunca descargó. Eso suponía el 74 % de ese informe y ocultaba las incidencias reales. Ahora el lado observado son las páginas que un sitemap debe declarar: descargadas, con respuesta 2xx, HTML, del mismo host e indexables. reconcile_sitemap recibe esa población como argumento comparable separado, así que SITEMAP_ORPHAN sigue comprobando la accesibilidad frente a todos los destinos de enlace y no puede inventar huérfanos. Lo que se descarta se devuelve en linked_not_comparable en lugar de eliminarse.

  • CorregidoFuncionaCorregir las comprobaciones de canonical en un sitio que sirve las dos formas de una URL,

    con y sin barra final (#95).

    norm_url elimina la barra final a propósito, así que un canonical escrito sin ella coincide con la página que sí la tiene. Pero el índice normalizado guardaba solo una página por clave, y un rastreo de un sitio WordPress típico tiene dos: /x (301) y /x/ (200). Leer la que se insertó primero hacía que CANONICAL_TO_REDIRECT marcara 78 páginas activas cuyo canonical responde 200. AuditContext ahora expone pages_by_norm con todas las páginas bajo cada clave, page_by_norm devuelve la variante que respondió 2xx, y CANONICAL_TO_REDIRECT y CANONICAL_NON_INDEXABLE solo se activan cuando ninguna variante los contradice.

  • CorregidoFuncionaCorregir size_bytes: ahora es el cuerpo de la respuesta tal como llega por la red,

    medido antes de decodificarlo (#99). Antes se medía a partir de la cadena ya decodificada, así que cada byte que no era UTF-8 válido se convertía en U+FFFD y se volvía a codificar como tres bytes. Un WebP de 739 KB de un rastreo real se registraba como 1,27 MB, y el factor de inflación variaba de un archivo a otro. Se sobrestimaban imágenes, PDF, fuentes y HTML servidos en un juego de caracteres heredado (windows-1251), y también el ratio de texto calculado sobre ese denominador. La caché HTTP guarda el tamaño en red junto con la entrada, así que una página reproducida informa lo mismo que informó la descarga en vivo. Su esquema pasa a http_cache.v2, y las entradas v1 se vuelven a descargar una vez en lugar de reproducirse sin tamaño.

  • AñadidoFuncionaAñadir docs/TOOL_REFERENCE.md, generado a partir de las definiciones de herramientas

    MCP (seohead/mcp/tool_reference.py, scripts/generate_tool_reference.py): los argumentos de cada herramienta seo_*/sf_* con su tipo y valor por defecto, su coste (red, escrituras, idempotencia, gasto; se lee de su perfil ToolAnnotations) y las notas sobre comportamiento y modos de fallo de su propia docstring. tests/test_docs_drift.py hace fallar la compilación si el documento se desvía de las definiciones de herramientas o si falta alguna herramienta.

  • AñadidoFuncionaAñadir tests/test_docs_commands_execute.py: extrae cada comando seohead ... que

    aparece en README, docs, skills y ejemplos (scripts/doc_commands.py) y lo ejecuta sin conexión, contra un sitio de prueba en bucle local (tests/doc_fixtures/) y contra copias materializadas de examples/, comprobando que termine sin errores. Los comandos que necesitan infraestructura real (RDAP/DNS, un binario de SF con licencia, una credencial de proveedor de pago, el servidor mcp, que nunca termina) al menos se analizan con el parser de argumentos en vivo. Un comando documentado que deja de funcionar ahora hace fallar la CI en lugar de publicarse desactualizado.

  • CambiadoFuncionaReestructurar las 21 skills técnicas de flujo de trabajo (.claude/skills/*/SKILL.md)

    con una forma común: Trigger, Anti-trigger, Preconditions (como lista de comprobación), el Workflow existente, Decision points, Definition of done (como lista de comprobación) y Cost. Corregir el recuento obsoleto de cobertura de comandos al final de docs/SKILLS.md. El recuento real, calculado escaneando cada archivo de skill, lo verifica ahora una nueva prueba de drift.

  • CorregidoFuncionaCorregir varios recuentos de herramientas y pruebas que se habían desfasado sin avisar de

    los registros reales (un recuento…

    Corregir varios recuentos de herramientas y pruebas que se habían desfasado sin avisar de los registros reales: un recuento obsoleto de comandos CLI en docs/USAGE.md, docs/COMPARISON.md, README.md y docs/TESTING.md, un recuento obsoleto de herramientas MCP en docs/TOOLS.md, un recuento obsoleto de herramientas de referencia en docs/README.md y el número de pruebas sin conexión. Los valores corregidos quedan fijados con una prueba de regresión (test_stale_tool_counts_do_not_reappear).

  • AñadidoFuncionaAñadir las cuatro auditorías estáticas de Lighthouse que no necesitan navegador ni API de

    terceros (#59): MISSING_CHARSET, MISSING_DOCTYPE, VIEWPORT_MISSING y NO_COMPRESSION, cada una calculada a partir de evidencia que ya contiene un rastreo. content_encoding, meta_charset, doctype y viewport se suman al vocabulario normalizado de columnas, de modo que una exportación de SF que los traiga como columnas de Custom Extraction alimenta las mismas comprobaciones. El registro crece de 114 a 118 comprobaciones.

  • CambiadoFuncionaConectar los diez ajustes restantes del rastreador que estaban validados y escritos en el

    manifiesto de la ejecución…

    Conectar los diez ajustes restantes del rastreador que estaban validados, se escribían en el manifiesto de la ejecución y --config-help describía, pero que nada leía (#63). limits.max_response_bytes, speed.max_delay_seconds, robots.user_agent_token y speed.stop_after_consecutive_timeouts ahora configuran un comportamiento que antes estaba fijado en el código. robots.unavailable_means_stop decide si un robots.txt inaccesible o con error 5xx detiene el rastreo o se trata como sin restricciones. Antes, un robots.txt inaccesible nunca detenía el rastreo, sin importar la política, mientras que uno con 5xx siempre lo hacía. Ahora ambos casos son el mismo caso «no disponible», regulado por el ajuste. limits.max_url_length, limits.max_query_variants_per_path, http.retry_on_timeout y discovery.follow_nofollow son comportamientos nuevos. http.user_agent se aplica ahora a las peticiones reales, en lugar de enviar siempre el agente por defecto del toolkit. Se añaden crawl-describe-settings (CLI) y seo_crawl_describe_settings (MCP) para que un agente pueda descubrir la superficie de configuración sin acceso al sistema de archivos (#23).

  • AñadidoFuncionaAñadir búsqueda personalizada (tools/custom_search.py) y extracción personalizada

    (tools/custom_extract.py) sobre un corpus ya rastreado: filtros de presencia y ausencia (código fuente sin procesar, texto visible, un elemento CSS con nombre o un nodo XPath) y extractores CSS/XPath/regex. Ambos informan sobre qué representación usaron: marcado estático frente al DOM renderizado. La ausencia se cuenta con honestidad: una página cuya descarga falló se excluye tanto del numerador como del denominador, en lugar de contarse como ausente. La extracción ejecuta cada par (documento, extractor) con un presupuesto de tiempo real (SIGALRM en POSIX). Una expresión patológica aborta solo ese documento, y la ejecución termina igualmente.

  • AñadidoFuncionaAñadir la clasificación de la posición de los enlaces (tools/link_position.py): nav,

    cabecera, barra lateral, pie o contenido, mediante una regla ordenada sobre la ruta de ancestros de cada enlace. Reutiliza la noción de contenido de content_area.py en lugar de inventar una segunda. Se conecta a la grabación de enlaces de crawl/spider.py tras link_position.classify (desactivada por defecto, porque guardar una posición por enlace consume memoria en un rastreo grande). Se agrega a nivel de sitio mediante inlink_composition de crawl/linkgraph.py, que ahora alimenta una nueva incidencia de auditoría, INLINK_BOILERPLATE_ONLY, para las páginas enlazadas solo desde elementos de plantilla. El registro pasa de 104 a 105 comprobaciones.

  • AñadidoFuncionaAñadir ocho cálculos de segunda pasada tras el rastreo, que solo se pueden responder

    cuando este ha terminado…

    Añadir ocho cálculos de segunda pasada que solo se pueden responder cuando el rastreo ha terminado (issue #15): una puntuación de enlaces internos calculada a partir del grafo de aristas all_inlinks (LOW_LINK_SCORE); una URL canónica a la que ningún hipervínculo apunta (UNLINKED_CANONICAL); la detección de bucles y de series sin enlazar en rel="next" (PAGINATION_LOOP, UNLINKED_PAGINATION_SERIES); la reciprocidad de hreflang (HREFLANG_MISSING_RETURN_LINK); agregados de composición de enlaces entrantes (ONLY_NOFOLLOW_INLINKS, ONLY_NONINDEXABLE_SOURCE_INLINKS); la ruta de descubrimiento más corta y concreta desde la semilla del rastreo (DEEP_DISCOVERY_PATH); un respaldo calculado internamente para contenido mixto (INSECURE_SUBRESOURCE); y la agrupación de casi duplicados a partir del texto de página almacenado (NEAR_DUPLICATE/DUPLICATE_BY_HASH). Esta última conecta por primera vez tools/duplicate.py y tools/content_area.py a la auditoría. ORPHAN_PAGE, SITEMAP_ORPHAN y las dos comprobaciones nuevas de «sin enlazar» ahora se omiten. Se informan como un salto con nombre, no como incidencia, en un rastreo que el agregador ha marcado como parcial, porque «nada enlaza aquí» no se puede demostrar en un rastreo truncado. El registro pasa de 104 a 114 comprobaciones.

  • CambiadoFuncionaAuditar el registro de rastreo frente a una lista externa de SEO técnico y cerrar ocho

    huecos baratos y verificados…

    Auditar el registro de rastreo frente a una lista de comprobación externa de SEO técnico y cerrar ocho huecos baratos y verificados: cinco comprobaciones de hreflang (códigos de idioma o región no válidos, falta de autorreferencia, falta de x-default, entradas duplicadas y destinos no canónicos), dos directivas de robots (notranslate y unavailable_after) y URL canónicas que contienen un fragmento. El registro pasa de 96 a 104 comprobaciones. Consulta docs/CHECKLIST_AUDIT.md.

  • AñadidoFuncionaAñadir asset-weight-check: descarga el CSS/JS enlazado de una página e informa de

    recursos que bloquean el renderizado…

    Añadir asset-weight-check: descarga el CSS/JS enlazado de una página e informa de los recursos que bloquean el renderizado, los archivos demasiado grandes, las bibliotecas duplicadas (por hash de contenido), la falta de minificación, la ausencia de font-display, el JS polyfilled heredado y la falta de compresión o de caché de larga duración.

  • AñadidoFuncionaAñadir crawl-site --sitemap <url> (y sitemaps.auto_discover en --config): alimentar

    el rastreador nativo con las URL declaradas en un sitemap, seguir los enlaces de cada una y cotejar los conjuntos declarado y observado en summary.sitemap de audit.json. Se usan los mismos identificadores de comprobación, SITEMAP_ORPHAN / URL_NOT_IN_SITEMAP, que ya informa el flujo de Screaming Frog.

  • AñadidoFuncionaAñadir crawl-site --config-help, generado desde seohead/crawl/config.py, y ocultar

    --max-depth y --min-delay en --help (siguen aceptándose), para que la superficie de flags deje de crecer con cada ajuste del rastreador.

  • CambiadoFuncionaDividir la detección de tecnologías (fingerprinting) en un paso de descarga y en un paso

    puro analyze_tech, capturar los identificadores de analítica y de gestores de etiquetas en lugar de solo sus nombres, y añadir un informe tag_coverage que agrupa la presencia por plantilla de URL y marca cómo se midió cada página.

  • CambiadoFuncionaResolver cadenas y bucles de redirección como segunda pasada sobre los destinos de

    redirección de un rastreo terminado…

    Resolver cadenas y bucles de redirección como segunda pasada sobre los destinos de redirección propios de un rastreo terminado. Así, REDIRECT_CHAIN/REDIRECT_LOOP ya no dependen del informe nativo Redirect Chains de Screaming Frog: una exportación con perfil ligero o una ejecución de crawl-site obtiene las mismas incidencias sin coste adicional.

  • AñadidoFuncionaAñadir un área de contenido configurable (content_area.py) que limita el recuento de

    palabras a la región principal, excluyendo de forma predeterminada la navegación y el pie, sin afectar al descubrimiento de enlaces. La estrategia resuelta se informa por página.

  • CambiadoFuncionaSeparar los duplicados exactos de los casi duplicados en duplicate.py: las

    coincidencias exactas se calculan con hash a partir del texto extraído (no de los bytes en bruto) y se excluyen de los grupos de casi duplicados. Además, las comparaciones solo consideran páginas indexables de forma predeterminada.

  • AñadidoFuncionaAñadir un informe de consistencia de plantillas (boilerplate_report.py) que calcula el

    hash de cabecera, navegación y pie de cada página, y marca los grupos de plantilla minoritarios.

  • AñadidoFuncionaAñadir extracción de Markdown sin dependencias (markdown_extract.py): una renderización

    solo del área de contenido y otra del documento completo.

  • CambiadoFuncionaConectar markdown_extract y boilerplate_report a la CLI y a la superficie MCP como

    markdown-extract/seo_markdown_extract y boilerplate-report/seo_boilerplate_report (47 herramientas básicas, frente a 45 antes). Además, añadir a la firma MCP de seo_duplicate_check la marca only_indexable, que duplicate_check ya tenía en la capa de handlers y donde se había pasado por alto. La ruta de URL de citability-check pasa a usar el Markdown del área de contenido de markdown_extract en lugar del campo text del parser. Ese campo es el documento entero, una sola línea colapsada sin saltos de párrafo ni de encabezado. Con este cambio se corrigen dos problemas: la dilución por plantilla que planteaba el issue y un error latente. El texto plano anulaba en silencio las dimensiones Answer Blocks y Structure Quality en cada URL en directo. Sin limitar a propósito quedaron dos cosas. La primera es el propio campo text del parser, que sigue siendo de todo el documento, porque la extracción de evidencia de esquema de page_facts.py (enlaces sociales sameAs, migas de pan, expresiones regulares de precio y valoración) depende de datos que legítimamente viven en los widgets de cabecera y pie que el área de contenido excluye. La segunda son las comprobaciones THIN_CONTENT/LOW_TEXT_RATIO de sf/core/rules.py, cuyos word_count/text_ratio vienen de las columnas de exportación de Screaming Frog. Son datos de terceros que el toolkit no puede reducir sin HTML en bruto, lo que obligaría a descargar de nuevo cada página y rompería el diseño offline sin peticiones de la auditoría SF. El crawler propio (crawl-site) ya hereda el alcance del área de contenido sin coste, porque su recuento de palabras se lee directamente de parser.parse_html.

  • CambiadoFuncionaDocumentar una convención de nombres (docs/NAMING.md) y resolver las colisiones de

    nombres base de módulo y los archivos de prueba nombrados por proceso que se encontraron. No cambió ningún nombre de comando CLI, handler ni herramienta MCP.

  • AñadidoFuncionaAñadir archivos de incorporación para la comunidad, las citas y los agentes que no

    necesitan clave.

  • AñadidoFuncionaAñadir la skill de flujo de trabajo con permisos analytics-console-review y tres

    recetas prácticas.

  • CambiadoFuncionaDocumentar el soporte de la línea de seguridad actual 3.x.
  • CambiadoFuncionaExigir TLS 1.2 o superior y fijar las sondas directas de certificados a direcciones

    públicas ya validadas.

  • AñadidoFuncionaAñadir una caché de respuestas HTTP para crawl-site (seohead/crawl/cache.py,

    activable mediante cache.mode; por defecto off, para que ningún efecto secundario quede oculto tras un valor predeterminado). Incluye semántica real de frescura HTTP (max-age/Expires, revalidación con ETag/Last-Modified, variantes sensibles a Vary, y respeto de no-store/no-cache). Un modo replay sirve para depurar; queda reflejado en el manifiesto y nunca es el valor por defecto. Un flag invalidate fuerza una recarga explícita. Cada página descargada lleva cache_status (hit/revalidated/miss). La ejecución lleva cache_stats y cache_replay tanto en la salida del handler como en el bloque run de audit.json, de modo que un informe construido en parte desde la caché lo indica. Un acierto de caché no cuesta ninguna petición ni consume el retardo de throttle ni un hueco del gate de envío concurrente: la espera se emite desde dentro de fetch_one, solo cuando está a punto de producirse una ida y vuelta real a la red.

  • AñadidoFuncionaAñadir reutilización basada en el journal a seohead/core/runlog.py

    (SEOHEAD_REUSE_POLICY, una edad máxima por herramienta…

    Añadir reutilización basada en el journal a seohead/core/runlog.py (SEOHEAD_REUSE_POLICY, una edad máxima en segundos por herramienta; por defecto vacía, lo que significa que nunca se reutiliza nada). Una respuesta anterior configurada, todavía fresca y correcta, se devuelve en lugar de volver a llamar a la herramienta. Se marca con reused: true y reused_from_ts, tanto en el resultado como en la nueva entrada del journal que sigue escribiéndose. La frescura siempre se mide desde el momento en que el valor se obtuvo de verdad, y la propia reutilización nunca la prolonga.

Versión

3.0.0

Primera instantánea pública30 de agosto de 2026
10 entradas · Primera instantánea pública10 cambiado

30 de agosto de 2026

10 cambiado
  • CambiadoFuncionaUn único paquete de Python con 42 herramientas CLI/MCP compartidas.
  • CambiadoFuncionaCinco herramientas MCP adicionales de Screaming Frog y un analizador de rastreo con 96

    comprobaciones.

  • CambiadoFuncionaReconocimiento de dominio, CDN, tecnología, seguridad, espejos, regiones, bots y

    backlinks.

  • CambiadoFuncionaValidación de Schema.org y generación de grafos de datos conectados.
  • CambiadoFuncionaEvidencia del sitio acotada a partir del sitemap e informes en XLSX, DOCX, CSV, Markdown

    y JSON.

  • CambiadoFuncionaIntegraciones opcionales con Wordstat, SERP de Yandex, Arsenkin, Metrika y DataForSEO.
  • CambiadoFuncionaVeintiuna skills técnicas de flujo de trabajo y siete playbooks de SEO empaquetados.
  • CambiadoFuncionaMCP local por stdio y soporte de Docker; sin GUI, API alojada ni telemetría.
  • CambiadoFuncionaREADME público basado en evidencias, con visuales reproducibles de auditoría sintética,

    tareas, interfaz e informes.

  • CambiadoFuncionaPublicación sin historial y avisos explícitos de terceros.

Fecha = el día en que llegó el cambio (fecha git de su fragmento changelog.d/). Número = el issue que cierra. Título = primera frase, detalles al hacer clic.