Journal des modifications

Ce qui a changé dans SpiderHead, version par version. Chaque entrée indique le type de modification et si elle fonctionne aujourd'hui.

Versions sur GitHub
En développement

Unreleased

Depuis 3.1.065 entrées

22 octobre 2026

7 modifié2 corrigé
  • ModifiéFonctionneA 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 (ticket sur GitHub)
  • ModifiéFonctionneA 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 (ticket sur GitHub)
  • CorrigéFonctionneCrawls 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 (ticket sur GitHub)
  • ModifiéFonctionneA 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 (ticket sur GitHub)
  • CorrigéFonctionnePages 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 (ticket sur GitHub)
  • ModifiéFonctionneAn 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 (ticket sur GitHub)
  • ModifiéFonctionneHrefs 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 (ticket sur GitHub)
  • ModifiéFonctionneHEADING_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 (ticket sur GitHub)
  • ModifiéFonctionneThird-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 (ticket sur GitHub)

21 octobre 2026

3 ajouté4 modifié3 corrigé
  • ModifiéBêtaApplication de bureau : le jeu de données d'URL en liste plate ou en arborescence de#1492

    chemins.

    Un bouton liste/arborescence en bas de la barre des groupes fait basculer le jeu de données entre la page plate et une arborescence de chemins repliable, construite sur les mêmes lignes et les mêmes filtres : les hôtes sont les nœuds de premier niveau, les URL de répertoire sont leurs propres dossiers, et les URL de documents se rattachent au dernier dossier. Sélectionner une feuille pilote la sélection partagée du tableau : les détails et les filtres sont conservés lors du changement.

    #1492 (ticket sur GitHub)
  • AjoutéBêtaApplication de bureau : mode relecture des données seules.#1495

    Affichage > Données seules (Ctrl+Alt+D) masque la navigation et la barre supérieure pour les longues sessions de relecture et ne laisse que les données. Ce choix est conservé pendant la session, et les panneaux de chaque écran continuent de répondre à leurs propres bascules.

    #1495 (ticket sur GitHub)
  • CorrigéBêtaLogs : accepter le temps de réponse en toute position et les formats à un seul ident.#1534

    Les analyseurs Apache extraient désormais le referer, le user-agent et le time-taken lorsque le temps de réponse se trouve entre la taille et le referer, ou en fin de ligne, au lieu d'ignorer silencieusement ces deux champs entre guillemets. La détection du format accepte un ou deux jetons ident entre l'IP du client et l'horodatage : le format nginx personnalisé à tiret unique s'importe désormais au lieu d'échouer en bloc. Le rapport d'import nomme les variantes acceptées (combined-2-ident, combined-1-ident). Corrige #1534 et #1535.

    #1534 (ticket sur GitHub)
  • ModifiéBêtaApplication de bureau : l'échelle d'espacement est terminée, plus aucune marge hors#1374

    échelle.

    Les 184 appels setContentsMargins/setSpacing restants hors échelle, répartis sur 60 fichiers, passent à l'échelle de jetons avec une correspondance qui ne fait que resserrer. Le test de cliquet (ratchet) échoue désormais sur toute valeur hors échelle. Recherche, images, boîte de réception, issues, logs, journal et intégration ont été normalisés en premier.

    #1374 (ticket sur GitHub)
  • ModifiéBêtaApplication de bureau : gains rapides, valeurs TSV brutes, projet dans le titre de la

    fenêtre, texte tertiaire conforme AA.

    copy_tsv colle les valeurs stockées, si bien que le texte d'espace réservé « pas de données » n'atteint jamais un tableur ; le titre de la fenêtre affiche le projet ouvert (Projet — SpiderHead) ; le texte tertiaire respecte désormais le contraste AA sur les surfaces surélevées.

  • CorrigéBêtaApplication de bureau : régions clavier honnêtes, Entrée ouvre les détails, sources

    d'erreur lisibles.

    F6 parcourt uniquement la navigation et la page courante. Entrée ouvre les détails de la ligne sélectionnée, comme le promettait toujours le menu de ligne. Les erreurs de lecture dans la barre d'état nomment l'opération (tableau d'URL, paramètres de crawl) au lieu de l'identifiant brut de la requête.

  • ModifiéBêtaApplication de bureau : le menu Affichage se lie aux panneaux propres à l'écran courant.

    Un écran peut exposer panel_actions(), c'est-à-dire des triplets (titre, affiché, bascule), et le menu Affichage construit sa section des panneaux à l'ouverture de l'écran. L'écran des URL propose son résumé de passage et le mode tableau seul ; les anciens éléments d'audit restent sur leur propre page.

  • CorrigéBêtaApplication de bureau : les ticks d'activité n'inondent plus les journaux des fenêtres

    fermées.

    Le signal global d'activité continuait d'appeler des widgets BusyIndicator supprimés. Les fenêtres fermées restent désormais silencieuses.

  • AjoutéBêtaApplication de bureau : les onglets du mode simple peuvent être masqués et restaurés.

    Menu contextuel de la barre d'onglets : masquer un onglet, restaurer les onglets masqués, tout afficher. Le choix est conservé. Le premier onglet reste toujours, le dernier onglet visible ne peut pas être masqué, et un onglet masqué réapparaît lorsque la Vue d'ensemble y mène.

  • AjoutéBêtaApplication de bureau : états du mode simple, barre de marque et captures hors ligne.

    Panneaux d'état avec actions : aucun résultat (effacer la recherche / tout afficher), échec (réessayer / afficher le journal), noyau introuvable (ouvrir les paramètres). Un avis d'arrêt compte les URL explorées et en file d'attente. La barre d'outils porte le logo de marque (une araignée), et le compteur d'erreurs est un badge.

20 octobre 2026

1 ajouté3 modifié
  • ModifiéBêtaLe paquet CLI seohead est découpé en modules par domaine.#1514

    cli/_shared.py contient les registres de commandes et les aides de saisie. checks_cmds, project_cmds, scan_cmds, crawl_cmds, sources_cmds, reports_cmds et misc_cmds portent chacun leur tranche de l'ancien mapping d'arguments nommés de cli/__init__.py, des options argparse et des cas particuliers du dispatch principal. La surface d'import publiée est inchangée et le module passe de 4 506 à 513 lignes. La sortie de --help reste identique octet pour octet pour chaque commande.

    #1514 (ticket sur GitHub)
  • ModifiéBêtaLes handlers MCP passent dans un paquet dédié.#1514

    Les handlers du serveur vivent désormais dans seohead/mcp/handlers/, répartis par domaine : projets, trafic, logs, sources, contenu, sémantique, workflow, scans conservés, preuves et export BI, environnement et catalogue. La documentation et les références aux chemins des sources suivent la nouvelle structure.

    #1514 (ticket sur GitHub)
  • ModifiéBêtaTableau d'URL : sélection de plusieurs lignes avec copie TSV de la sélection.#1347

    Finition du tableau d'URL de #1347 : sélectionnez plusieurs lignes et copiez exactement la sélection au format TSV.

    #1347 (ticket sur GitHub)
  • AjoutéBêtaNoyau de contrôle du débit de crawl en direct (en cours).#1360

    Le noyau qui permet de modifier le débit du crawl pendant qu'un scan tourne (#1360). Le câblage dans l'application de bureau suit.

    #1360 (ticket sur GitHub)
Jours plus anciens (4)Show all

14 octobre 2026

3 modifié
  • ModifiéBêtaApplication de bureau : progression du scan, limite d'URL, bouton d'arrêt et motifs de#1358

    fin.

    Traitées, en file, vitesse et ETA, ainsi que la limite d'URL demandée, s'affichent dans la liste des scans, le détail du scan et la carte de navigation. Le bouton d'arrêt de la barre supérieure s'intitule « Arrêter le scan » au lieu d'un identifiant d'exécution, se met à jour sans scintillement et disparaît une fois l'exécution terminée. Les exécutions finies indiquent pourquoi elles se sont arrêtées (limite d'URL, de requêtes ou de temps, erreurs, disque).

    #1358 (ticket sur GitHub)
  • ModifiéBêtaApplication de bureau : un seul système de boutons, marges de page standard, sans puces

    indisponibles.

    Un seul système de boutons sur tous les écrans, des marges de page standard, et les puces des fonctions indisponibles sont retirées.

  • ModifiéBêtaApplication de bureau : le générateur de redirections et l'éditeur de snippets passent

    dans une section Outils.

    Méthodes ne contient plus que le catalogue des méthodes et affiche le scan sélectionné à l'ouverture. L'éditeur de snippets présélectionne le contexte du scan sélectionné.

13 octobre 2026

3 modifié
  • ModifiéFonctionneCrawler de bureau : onglets de détail d'URL (liens entrants, sortants, ressources,#1349

    snippet, source enregistrée, en-têtes) sur le fichier de crawl, filtres par onglet avec compteurs, vue d'ensemble plus complète avec les directives, sélecteur de colonnes par onglet relié aux colonnes d'export, tri par en-tête, menu contextuel et navigation au clavier. Nouveau scan peut enregistrer ses réglages comme profil de crawl nommé.

    #1349 (ticket sur GitHub)
  • ModifiéFonctionneSurfaces mortes du bureau : la section Graphe de liens lit les totaux de nœuds, d'arêtes#1347

    et d'orphelines, et une page…

    Surfaces mortes du bureau : la section Graphe de liens lit les totaux de nœuds, d'arêtes et d'orphelines, ainsi qu'un tableau paginé de nœuds, depuis la commande scan-graph du noyau, au lieu d'un espace réservé. Problèmes liste les plus gros groupes de contrôles à partir des compteurs par contrôle du noyau. Le tableau d'URL affiche et trie la colonne Liens entrants, avec un repli et une note lorsqu'un scan n'a conservé aucune observation de liens ; la colonne Nombre de problèmes, jamais mesurable, n'est plus proposée. Export et rapports exécutent la commande scan-export du noyau pour les pages ou les constats, en CSV, XLSX, JSON ou XML, dans un dossier choisi. Les jeux de données de comparaison et de tâches, la colonne d'espace réservé et l'historique des exports que le noyau ne peut pas soutenir sont supprimés. Les réglages stockés mais pas encore appliqués sont désormais visiblement désactivés, avec la raison au survol. Le dialogue de configuration du crawl liste une fois, en lecture seule, les paramètres sans éditeur validé, au lieu de les mélanger à la liste de l'éditeur, et le champ « Pourquoi ce scan » du Nouveau scan explique pourquoi il est vide.

    #1347 (ticket sur GitHub)
  • ModifiéFonctionneSurfaces mortes du bureau : la section Crawler lance désormais un crawl ad hoc sans#1347

    projet. Le champ d'adresse, le sélecteur Site/Liste/Sitemap, la limite d'URL, Démarrer/Arrêter, les onglets de contrôle, la recherche d'adresse, les compteurs de la vue d'ensemble, le volet de détail et l'export CSV/XLSX sont reliés aux commandes du noyau crawl-site --scan-out et scan-url-query. La barre d'état affiche la vitesse, les pages explorées et les pages restantes fournies par le noyau. Rien ne démarre à l'ouverture de l'écran, et le résultat temporaire est supprimé à Effacer, au crawl suivant et à la fermeture de l'application. Les entrées du menu de crawl rapide ouvrent la section. Le badge « Indisponible dans cette version du noyau » de la barre supérieure est retiré. La comparaison n'affiche plus d'état d'erreur après une lecture de projet : une comparaison vidée est une invite neutre pour choisir deux scans, et seul un échec réel affiche l'état indisponible.

    #1347 (ticket sur GitHub)

12 octobre 2026

8 ajouté10 modifié2 corrigé
  • CorrigéFonctionneCorrection : compatibilité de la configuration de scan natif lors des mises à niveau et#1344

    des retours arrière.

    Correction de la compatibilité de la configuration de scan natif lors des mises à niveau et des retours arrière. Préserve l'en-tête et l'empreinte existants, conserve les nouvelles options effectives dans un contexte versionné, et garde le comportement historique des paramètres de suivi lorsque le contexte est absent. La reprise valide l'ensemble des réglages effectifs et refuse les artefacts non pris en charge ou incohérents.

    #1344 (ticket sur GitHub)
  • CorrigéFonctionneCorrection de la détection RDFa conservée : les IRI de propriétés relatives et les hôtes#1344

    non liés n'établissent plus de balisage Schema.org. Les IRI de vocabulaire absolus et les préfixes reconnus sont préservés, et les tests de délai de recherche restent bornés grâce à des motifs de fixtures peu coûteux.

    #1344 (ticket sur GitHub)
  • ModifiéFonctionneGarder les onglets compacts des paramètres de projet dans la fenêtre, et exposer les#1315

    réglages supplémentaires via…

    Garder les onglets compacts des paramètres de projet dans la fenêtre et exposer les réglages supplémentaires via un menu de débordement. Masquer le sélecteur de planification redondant lorsque seul le site principal est disponible, tout en conservant la sélection entre sites liés, quelle que soit la taille de la fenêtre. - Afficher l'aperçu d'un User-Agent personnalisé seulement lorsque sa valeur est disponible ; ne pas présenter le libellé d'un préréglage comme l'en-tête réellement transmis. Préserver les limites de délai configurées du planificateur. - Réévaluer la création de tâches du propriétaire après l'actualisation du projet, et conserver les exécutions concurrentes validées par le noyau malgré les révisions de checklist sans rapport. La confirmation et les vérifications de révision courante restent obligatoires pour les écritures. - Désactiver la vérification de bot tant que les journaux de projet conservés ne sont pas disponibles, prendre en charge les appels ordinaires au modèle de table Qt, et afficher séparément les totaux d'incidents enregistrés, les échantillons d'URL bornés et les contrôles non mesurés. - Enregistrer les polices embarquées une seule fois par application, au lieu de les enregistrer en double à chaque changement de thème.

    #1315 (ticket sur GitHub)
  • AjoutéFonctionneAjout de la gestion des identifiants fournisseurs en écriture seule via le canal stdin de#1343

    la CLI locale, consentement GSC explicite…

    Ajout de la gestion des identifiants fournisseurs en écriture seule via le canal stdin de la CLI locale, d'un cycle de vie explicite du consentement OAuth GSC, et de la découverte de ressources de compte en aperçu seulement. Le choix du fournisseur et les écritures d'identifiants MCP restent soumis à des décisions explicites du propriétaire. - Ajout de constats bornés d'Inspection d'URL dans la sortie SF liée au projet, derrière l'option explicite --gsc-inspect, avec comptabilisation locale du quota par propriété et historique d'inspection conservé et filtré par liste blanche. SF joint aussi l'historique d'URL mesuré de GSC, GA4, Metrika et Cloudflare, sans appel implicite de fournisseur. Les constats par URL enregistrés entrent dans le flux ordinaire des problèmes d'audit, tandis qu'une couverture manquante ou partielle est signalée explicitement. - Ajout d'instantanés quotidiens agrégés par URL pour Cloudflare, d'import Logpull Enterprise explicite, d'import de NDJSON Logpush fourni par l'appelant via le magasin de logs local, et de lectures en lecture seule des réglages IA, des jeux de règles de redirection et WAF, et des tâches Logpush, activées par choix. Une capture Instant Logs, confirmée séparément et soumise au plan, utilise une courte session WebSocket bornée et ne conserve qu'un préfixe local plafonné. La route laisse intactes les sessions existantes et signale l'expiration par inactivité documentée par Cloudflare, car l'API Edge n'expose aucun point d'arrêt. Les flux des destinations Logpush restent la propriété du client et ne sont pas ingérés. - Ajout d'une opération explicite de backlinks JSON-RPC Moz actuelle, les métriques d'URL héritées restant le comportement par défaut, et conservation à null des reçus de dépense incertains dans les rapports du journal. - Ajout d'un lecteur borné du résumé des artefacts PageSpeed, qui valide la propriété et ne renvoie que les champs Lighthouse autorisés.

    #1343 (ticket sur GitHub)
  • ModifiéFonctionneLes profils de crawl nommés peuvent être inspectés en JSON validé, sélectionnés via#1299

    seo_crawl_site, et attribués comme valeurs par défaut du projet, les surcharges de crawl du projet se superposant par-dessus. - L'estimation de progression du crawl calcule le temps pour la frontière connue en cours et l'indique séparément de la durée totale du crawl. Les cibles de crawl normalisent par défaut les paramètres utm_* et fbclid. - Les scans natifs actifs du projet acceptent des demandes ponctuelles de pause et d'arrêt, par identifiant d'exécution et point de contrôle, via le chemin de reprise SQLite existant. - L'authentification HTTP Basic/Digest liée à l'hôte et la négociation zstd facultative des réponses utilisent des références d'environnement, un accord explicite, une authentification en HTTPS uniquement et des budgets de requêtes. Les résultats de crawl incluent des estimations de charge bornées et conservent une taille de disque inconnue comme null.

    #1299 (ticket sur GitHub)
  • AjoutéFonctionneAjout d'un résumé opérationnel de l'état du projet pour la progression active du#1291

    collecteur, la complétude du dernier scan…

    Ajout d'un résumé opérationnel de l'état du projet : progression active du collecteur, complétude du dernier scan, santé des dossiers, tâches ouvertes du projet principal, dernière activité d'agent enregistrée et taille persistée du dossier de scan. L'état de connexion reste inconnu sans battement de cœur en direct.

    #1291 (ticket sur GitHub)
  • AjoutéFonctionneAjout d'un contrat d'infos du noyau lisible par machine : révision et date de build#979

    vérifiées, outils CLI et MCP pris en charge, et compatibilité de l'application de bureau à la révision exacte. Ajout d'une commande doctor en lecture seule et d'un outil MCP correspondant, pour vérifier les prérequis locaux. seohead --version affiche la version du paquet. - Ajout de lectures conditionnelles opaques tenant compte de la révision pour project-observe et project-activity. Ajout de vérifications de version soumises à consentement et de téléchargements de wheel et de source vérifiés par somme de contrôle, avec progression, annulation et aucune installation automatique.

    #979 (ticket sur GitHub)
  • AjoutéFonctionneAjout d'estimations de pré-contrôle des étapes payantes et d'un historique de statut par#1298

    étape aux projets semantic-core. - Prise en charge des aperçus d'import CSV/XLSX mappés, des exports limités, de la lecture paginée des clusters, des sélections de page de destination (landing) auditées et d'insights locaux fondés sur des preuves.

    #1298 (ticket sur GitHub)
  • AjoutéFonctionneAjout d'actions de page et de préréglages bornés, activés par projet, aux crawls rendus,#1302

    avec différences d'éléments brut/rendu conservées…

    Ajout d'actions de page et de préréglages bornés, activés par projet, aux crawls rendus, de différences d'éléments brut/rendu conservées et d'échecs réseau du navigateur. Exposition de constats de débordement mobile, de taille de texte et de taille de cible à partir des mises en page rendues et capturées. Ajout d'une capture d'écran de la première vue et de métadonnées explicites sur la représentation du DOM.

    #1302 (ticket sur GitHub)
  • AjoutéFonctionneAjout des états exacts checks_run, checks_skipped, checks_disabled et du total du#1296

    registre dans les preuves des scans de projet enregistrés. Les compteurs évalués et ignorés restent disjoints, et une couverture d'audit manquante est signalée comme indisponible. - Les scans enregistrés exposent des fenêtres HTML statiques et rendues bornées, avec identité du scan et du document, empreintes du corps brut et du texte décodé, et pages de constats pour l'URL exacte, via les gestionnaires CLI et MCP partagés. Le détail d'URL inclut une fenêtre bornée du HTML source. Les preuves indisponibles ou ambiguës restent explicites. La comparaison de corps prend en charge les paires statique/rendu ainsi que les paires entre scans. - Le statut du scan indique l'état d'intégrité, l'identité du scan concerné, la disponibilité des points de contrôle et des compteurs de dommages nullables. Les archives de projet portables peuvent omettre tous les corps HTML, omettre les corps plus anciens que 30 ou 90 jours, ou ne conserver que les N scans reconnus les plus récents, tout en préservant les tables de preuves.

    #1296 (ticket sur GitHub)
  • ModifiéFonctionneRequêtes d'URL sur scans enregistrés étendues : nombre de liens conservés, filtres#1295

    titre/canonical/hreflang/sitemap, et facettes tenant compte de la source. Les mesures absentes de lien, de sitemap, d'hreflang ou d'audit restent indisponibles au lieu d'apparaître comme zéro. - Ajout de compteurs optionnels de sévérité et par contrôle pour l'ensemble du scan, issus du résumé d'audit enregistré, avec des états explicites par contrôle : déclenché, silencieux, ignoré, désactivé et indisponible. - Un index reconstructible de profondeur de clic le plus court est persisté à la fin d'une capture scan.v2 ou d'une réanalyse hors ligne. Les anciens fichiers de scan continuent de dériver la profondeur de leur graphe de liens conservé, dans le budget de requête. - Ajout de filtres de type et d'URL de ressource liés au document source, de compteurs d'occurrences et par type, d'états d'octets conservés, et d'agrégats de blocs et de poids dans les preuves de ressources enregistrées. Les déclarations indisponibles et les poids de récupération partiels restent explicites. - Capture dans scan.v2 des durées HTTPX TCP/connexion, TLS, attente des en-têtes de réponse et téléchargement du corps, lorsque le transport émet des événements de trace. Le DNS reste indisponible, car HTTPX n'expose aucun événement de résolution distinct ; son temps peut être inclus dans la connexion. Ajout de headers-analyze hors ligne pour les en-têtes expurgés et les preuves de phases enregistrés. - Ajout d'une lecture CLI/MCP de l'arborescence de répertoires via une agrégation SQLite temporaire, avec profondeur, nombre d'enfants, nombre de nœuds et taille de sortie bornés. Les lectures de chemin le plus court existantes restent disponibles via scan-link-inspect --view path. - Ajout de scan-link-inspect --view links --preset inlinks|broken_links pour les vues nommées des liens entrants internes et des cibles sortantes cassées. - La finalisation native scan.v2 et la réanalyse hors ligne tentent désormais une projection indexée facultative des requêtes d'URL, liée à la source, pour le nombre et les types de ressources des pages, les indicateurs de titre en double, la couverture et les facettes sans filtre. Les lectures ne l'acceptent que pour un scan terminé dont l'UUID, la révision des preuves, les capacités et l'URL de départ correspondent ; une remise en file invalide sa publication. Les anciens scans gardent le repli borné en lecture seule, sans migration scan.v1. Sur le jeu synthétique d'un scan terminé de 1 M de pages, avec HTML et images partagés, le producteur de projection réel a fini en 6,36 s, à 400,7 Mo de RSS maximal. Les médianes de cinq passes étaient de 5,23 à 43,38 ms pour les pages avec colonnes de ressources, 60,81 ms pour le filtre d'images et 5,38 ms pour toutes les facettes, dans les budgets de 200/300 ms ; 100 lignes d'images étaient exactes. Cela valide la performance synthétique des requêtes enregistrées, pas un crawl en direct de 1 M d'URL. Les facettes d'inlinks et de sitemap sont restées explicitement indisponibles, si bien que la réponse des facettes était partielle.

    #1295 (ticket sur GitHub)
  • ModifiéFonctionneLa checklist de projet v4 porte les assignés, les critères d'acceptation, les liens vers#1294

    constats et méthodes, bornes…

    La checklist de projet v4 porte les assignés, les critères d'acceptation, les liens vers constats et méthodes, des plafonds bornés d'URL concurrentes et des commentaires de tâche attribués en ajout seul, tout en continuant de lire les formats de couverture antérieurs. - L'acceptation d'un objectif de la boîte de réception crée sa tâche de checklist personnalisée et stable, avec l'objectif d'origine comme description. L'acceptation n'exécute ni ne termine la tâche. - Les vues de tâches et de rapports exposent des états de mesure honnêtes des URL touchées par tâche, ainsi que des KPI de tâches personnalisées. Les compteurs restent indisponibles lorsque les preuves conservées n'énumèrent pas les URL touchées.

    #1294 (ticket sur GitHub)
  • ModifiéFonctionneLes rapports Markdown, DOCX et XLSX liés au projet incluent les compteurs de tâches#1297

    personnalisées, l'assignation et l'acceptation…

    Les rapports Markdown, DOCX et XLSX liés au projet incluent les compteurs de tâches personnalisées, les champs d'assignation et d'acceptation, ainsi que la preuve nullable des URL touchées avec son état de mesure.

    #1297 (ticket sur GitHub)
  • AjoutéFonctionneAjout de métadonnées de catégorie et de rattachement au projet, avec pagination par#1312

    décalage, au catalogue d'outils MCP, et d'un lot borné de vérification d'URL pour des listes explicites ou des pages de scan conservées. - Ajout d'une qualité d'image automatique guidée par SSIM, d'un retrait explicite des EXIF et de rapports d'optimisation d'images sur les scans conservés. Ajout d'une sortie CSV de redirections WordPress Redirection, avec analyse locale des chaînes et des boucles. - Affichage dans l'aide des anciennes options de profondeur et de délai de crawl, en conservant leur comportement de compatibilité.

    #1312 (ticket sur GitHub)
  • AjoutéFonctionneLectures de flux compare.v2 bornées avec contrôles d'intégrité, tri et filtrage par URL ;#1300

    production d'un résumé Markdown borné et de fiches avant/après par URL exacte, qui conservent les observations manquantes comme « non revérifiées ». - Extension de l'historique d'URL enregistré avec les faits de page et les deltas entre scans adjacents ; les observations indisponibles ou absentes restent non comparables. - Persistance des points de contrôle de comparaison et des instantanés de progression pour une reprise à entrée identique, réutilisation des paquets terminés vérifiés comme succès de cache, et ajout de tranches de segment principal par changement ainsi que de preuves de codes de réponse des liens externes conservés.

    #1300 (ticket sur GitHub)
  • ModifiéFonctionneExtension du lecteur de données structurées conservées par URL exacte avec JSON-LD borné,#1304

    Microdata, RDFa, preuves de langue, traçabilité des sources et validation Schema.org hors ligne et locale.

    #1304 (ticket sur GitHub)
  • ModifiéFonctionneLa recherche de contenu conservée signale désormais des occurrences bornées, avec#1301

    décalages de caractères dans le texte source, lignes numérotées à partir de 1, navigation de correspondance par document et, facultativement, fenêtres expurgées de six lignes. Le filtrage par URL exacte s'exécute avant que SQLite ne classe les documents conservés. Les comptes complets de correspondances restent visibles lorsque la limite de 10 000 décalages ou de 64 Kio par enregistrement tronque les occurrences renvoyées, et la couverture est alors partielle. Les recherches par expression régulière sont indisponibles lorsqu'un délai mural ne peut pas être appliqué. Les corps indisponibles restent inconnus, jamais absents. - Les paquets de recherche indexés sont plafonnés à 512 Mio ; en atteignant la limite, un paquet explicitement incomplet est publié, avec sa couverture mesurée et la limite d'octets. - Ajout d'une route hors ligne d'échantillon d'extraction personnalisée pour du HTML fourni par l'appelant. Son URL facultative n'est qu'une étiquette et ne déclenche aucune récupération ; la récupération d'URL en direct reste une décision du propriétaire.

    #1301 (ticket sur GitHub)
  • ModifiéFonctionneImporter les lignes CSV de modification de snippets dans des tâches de relecture non#1010

    appliquées, mesurer la typographie locale selon un profil fourni par l'appelant, et ajouter des extraits de requêtes issus de scans conservés explicitement sélectionnés, avec traçabilité du document. Aucun seuil de moteur de recherche ni affirmation sur le rendu n'est inférée.

    #1010 (ticket sur GitHub)
  • ModifiéFonctionneLes crawls natifs enregistrés comparent les corps de réponse conservés avec un ensemble#1013

    borné de familles Content-Type reconnaissables. Les corps indisponibles, trop volumineux ou ambigus restent explicitement non mesurés.

    #1013 (ticket sur GitHub)
  • ModifiéFonctionneL'analyse d'images native conservée signale les déclarations de taille manquantes ou#1303

    invalides, ainsi que les alt vides informatifs ou mal formés…

    L'analyse d'images native conservée signale les déclarations de taille manquantes ou invalides, ainsi que les textes alternatifs vides informatifs ou mal formés, tout en préservant les alt="" décoratifs valides. Les images dotées d'un attribut alt littéralement absent restent des constats avec un nom ARIA ; les images décoratives visibles ont encore besoin de dimensions. - Les constats d'image conservent la portée source, cible et statut, la raison, le document et des emplacements ordinaux bornés. Les corps manquants préservent les faits positifs connus sur le nombre de pages, sans inventer d'URL d'image ni de réponse de ressource. Les erreurs de réponse d'image et les seuils d'octets conservent statut et raison. - La sélection d'images résout les pages sources après réouverture. Les preuves de ressources nomment les lignes conservées de récupération et de déclaration aux côtés des documents sources. L'identité native d'une image inclut la page source et la portée, ce qui empêche volontairement la fusion entre pages, et migre les anciennes empreintes d'images natives. Les anciens constats sans page source conservent leur identité précédente. Les éléments répétés gardent des comptes exacts et des échantillons d'emplacements bornés. - Le magasin synthétique (shop) conserve les défauts d'origine et 15 contrôles, et ajoute des cas de texte alternatif vide informatif et de taille manquante sur des produits existants, sans modifier les comptes de crawl.

    #1303 (ticket sur GitHub)

11 octobre 2026

16 modifié
  • ModifiéFonctionneExécuter la suite complète de l'outillage une seule fois sur Python 3.15 au lieu d'une

    matrice de versions plus anciennes, en conservant quatre groupes de tests vérifiés et une couverture combinée. Utiliser la même version stable de Python pour l'amorçage de la CI et des builds de publication.

  • ModifiéFonctionneConsolidation des contrôles d'audit conservés et des améliorations natives du bureau.

    Préserve les réglages de budget de ressources sans modifier l'en-tête figé du scan, conserve la réanalyse hors ligne et la reprise sûres, et partage les composants natifs des paramètres de projet, les jetons de thème et les polices embarquées. Retire les fichiers de conception privés de l'arborescence distribuée. - Lie les recontrôles de remédiation à la politique d'actifs effective validée, tout en préservant l'en-tête d'origine du scan et les octets source.

  • ModifiéFonctionneReconstruction des paramètres de projet Planification et Crawl avec des composants natifs#1323

    partagés, Roboto hors ligne…

    Reconstruction des paramètres de projet Planification et Crawl avec des composants natifs partagés (canvas), polices Roboto et Material Symbols hors ligne, et mise en page en colonne unique à 800 px. - L'interface de l'application reste entièrement en anglais, les contrats existants de commande de planification et de document sont conservés, et seules les données de planification adossées au noyau sont affichées. - Préserver les identités et alias des espaces de travail pendant que les paramètres du projet sont ouverts ; empêcher les enregistrements en double pendant que le noyau répond.

    #1323 (ticket sur GitHub)
  • ModifiéFonctionneLes paramètres de projet du bureau reçoivent un onglet Planification (jours de semaine,#1322

    jours du mois, fenêtre d'exécution, fuseau horaire, concurrents) et un onglet Crawl (mode de crawl, préréglage User-Agent ou chaîne personnalisée, pause entre requêtes, budget d'URL, SpiderHeadBot ou un user agent personnalisé). Les deux lisent et écrivent le projet via le noyau, et l'aperçu du projet affiche la prochaine et la dernière exécution planifiée. Un mode --tray exécute les scans dus du noyau et ne maintient le Mac éveillé que pendant qu'un scan tourne.

    #1322 (ticket sur GitHub)
  • ModifiéFonctionneLes audits natifs exposent désormais le balisage de tête bloquant le rendu, à partir du#1303

    HTML conservé complet, sans changer le schéma scan.v1 figé. Les corps manquants, incomplets ou limités par budget restent indisponibles. Les détections existantes de ressources de tête et l'entrée d'extraction personnalisée de SF sont réutilisées. - Ajout de budgets configurables d'octets pour la navigation observée et pour chaque ressource, de signaux de cache et de livraison des polices, d'heuristiques de minification et de scripts hérités, ainsi que de doublons exacts de scripts sur la même page, issus des preuves scan.v2 conservées. Les données non récupérées et les charges d'exécution incomplètes restent explicites. Les déclarations responsives ne sont pas additionnées comme poids d'exécution. Les bornes inférieures HTML seules, les compteurs de couverture scalaires, les échantillons de polices et les résumés de sources restent explicites et bornés. - Collecte de la couverture précise bornée JS/CSS de Chromium sur les rendus demandés, conservation de résumés d'usage UTF-16 et des constats de dimensionnement d'images rendues, puis lecture après réouverture ou réanalyse hors ligne. Les moteurs non pris en charge et les mesures manquantes ne deviennent pas des résultats propres. - Acceptation de JSON Lighthouse par URL, borné et correspondant, pour la découverte du LCP, les arbres de dépendances, les coupables de décalage de mise en page, la livraison d'images, les reflows forcés et les constats d'exécution des scripts, avec provenance de capture et empreintes des entrées. Aucun processus Lighthouse, fournisseur payant ni inférence de CWV terrain n'est ajouté. Mise à jour du registre, de la couverture SF et de la documentation de référence générée. - Les seuils d'actifs additifs restent hors de l'en-tête de scan natif figé, et leurs valeurs exactes sont stockées dans un contexte versionné et validé. La reprise compare ces valeurs séparément, et la réanalyse hors ligne les restaure depuis les preuves conservées. Les anciens lecteurs légers peuvent toujours inspecter la forme inchangée de la configuration d'en-tête.

    #1303 (ticket sur GitHub)
  • ModifiéFonctionneConservation des preuves AMP statiques et d'accessibilité liées au document dans les#1304

    lignes de contexte de scan existantes, en préservant le schéma SQL scan.v1 figé. Les constats AMP structurels inspectent le doctype d'origine, la structure head/body, le charset UTF-8, la viewport, le script d'exécution et les déclarations de boilerplate. Les cibles AMP appariées sans marqueur de racine AMP sont identifiées séparément. Les règles complètes du validateur AMP restent indisponibles dans l'attente d'une décision de licence. - Démarrage des constats d'accessibilité sur la langue du document, les étiquettes de formulaires, les alternatives d'images, les sauts de titres et le repère principal. Les constats préservent des exemples bornés et les comptes complets d'occurrences. Le contraste calculé et les règles axe-core rendues restent non mesurés. - Validation des microdonnées Schema.org et des sujets et propriétés RDFa courants, avec le vocabulaire fourni et les règles existantes de résultats enrichis. Les erreurs, avertissements et propriétés obligatoires manquantes conservés par URL deviennent des constats natifs. Les constructions RDFa non prises en charge constituent une preuve partielle explicite, et non un résultat de validation propre. - Service des arbres JSON-LD analysés, avec pour chaque bloc la source, la position et les erreurs de syntaxe, dans scan-structured-blocks ; plafonnement des arbres de propriétés larges et exposition de leur limite. Lecture du dernier document pour une URL et une représentation demandées, sans modifier son scan. - Préservation des preuves structurées partielles ou indisponibles, sans masquer les erreurs confirmées des voisines. Résolution des identités JSON-LD prises en charge par rapport à la même base de document que le balisage HTML, tout en préservant le JSON source. Rejet des blocs JSON scalaires ou vides comme graphes valides, et partage de la sélection normalisée des balises JSON-LD vivantes entre l'analyseur et les projections servies.

    #1304 (ticket sur GitHub)
  • ModifiéFonctionneConservation des attributs canonical et de pagination bruts comme contexte de document#1305

    versionné, sans modifier le SQL de scan figé. Les liens canoniques dotés d'attributs hreflang, lang, media ou type non pris en charge, les annotations mal formées et les déclarations inter-hôtes ou inter-protocoles produisent désormais des constats liés aux preuves. Les mots-clés de relation bien formés mais inconnus restent non classés. - Extension des sondes bornées d'URL cible du même hôte à la pagination, et conservation des observations mesurées de noindex et de canonical. Les chaînes canoniques natives et les constats noindex canonical/hreflang peuvent utiliser les sondes ; les anciennes sondes ne portant que le statut restent lisibles et non mesurées pour les directives HTML. - Jugement des chaînes de pagination natives opaques pour détecter les contradictions réciproques explicites next/prev, en conservant les règles numérotées ou par pas et les états nommés non jugés. Sélection des URL de constats enregistrées, y compris les membres groupés, via scan-url-query, à l'aide de tables SQLite temporaires et de preuves audit.v2 en flux. - Les jetons de relation Unicode inconnus et ceux contenant de la ponctuation restent non classés. Les autorités canoniques IDN et de port par défaut équivalentes sont normalisées, et les chemins cibles de pagination natifs exacts sont préservés. Les jetons de page mixtes illisibles restent non jugés. L'anomalie de pagination de la boutique est détectée même lorsque la page un n'a aucun numéro dans son URL. - Le rendu des annotations next/prev déclarées de la boutique fait que sa vérité terrain de pagination D41 est réellement servie et peut être validée par la capture native.

    #1305 (ticket sur GitHub)
  • ModifiéFonctionneLes journaux serveur conservent désormais des totaux exacts d'IP de bots sur disque au#1311

    lieu d'un échantillon plafonné, avec des bornes…

    Les journaux serveur conservent désormais des totaux exacts d'IP de bots sur disque au lieu d'un échantillon plafonné, avec des enregistrements par IP bornés, des visites, la dernière visite et des filtres par sous-réseau. La vérification DNS explicite contrôle séparément chaque IP sélectionnée, enregistre les preuves PTR et de résolution directe, prend en charge IPv6, et conserve les résultats indisponibles ou au délai dépassé comme non vérifiés. Les caches locaux expirent après une heure ; les lectures ne déclenchent jamais de DNS. - Ajout de l'import local des journaux de projet, du résumé paginé, des commandes de preuves de bots et de jointure avec les scans natifs, via les gestionnaires CLI/MCP partagés. Les artefacts de logs séparés conservent les partitions par date, la couverture et la provenance des sources, sans modifier les schémas de scan figés. Les preuves manquantes ou incomplètes retiennent les conclusions d'absence. Les écrans de logs du bureau font l'objet d'un suivi de présentation distinct.

    #1311 (ticket sur GitHub)
  • ModifiéFonctionneLes audits natifs conservés regroupent désormais les liens internes cassés par cible#1306

    observée, avec preuves source/ancre…

    Les audits natifs conservés regroupent désormais les liens internes cassés par cible observée, avec preuves de source et d'ancre, enregistrent les chaînes et boucles de redirection avec statuts par saut, distinguent la recherche interne basée sur le chemin et les ancres vides, et exposent les résultats externes sans réponse capturés. Les constats de cohérence du sitemap et du robots.txt utilisent l'appartenance conservée et les preuves de réponse, sans nouvelle récupération en direct ; les preuves manquantes ou partielles restent explicites. - Ajout d'un graphe de liens conservé et borné, avec filtres de position, de section et de voisinage local, agrégation par section et changements d'arêtes d'un scan à l'autre. La réanalyse hors ligne rétro-remplit les positions par lots dérivés reprenables, et signale les preuves non classées dans l'inspection des liens et le statut du scan, sans modifier le schéma scan.v1 figé. - Ajout d'une génération locale de sitemap XML à partir des pages 200 conservées, canoniques et indexables, avec lastmod observé, exclusions, découpage par protocole, index de sitemaps et sitemap d'images facultatif. La CLI et le MCP partagent les mêmes implémentations ; la publication exige un dossier local neuf et ne déploie jamais de fichiers. - Préservation des cibles de découverte manquantes, capturées au moment de la capture, lorsque le traitement ultérieur du sitemap ou des graines (seeds) ajoute l'URL au catalogue conservé. Les preuves expliquées de non-résolution ou d'exclusion restent immuables, tandis que les cibles connues revendiquées et les incohérences d'identité non nulles restent invalides. - Le sitemap d'images exclut les réponses de ressources non-200 connues, même lorsque la ressource n'a pas été stockée comme page explorée, et marque les réponses d'images non mesurées comme couverture partielle.

    #1306 (ticket sur GitHub)
  • ModifiéFonctionneContrôler les appels de production Google DataForSEO avant la construction du client,#1310

    exposer des devis hors ligne…

    Contrôle des appels de production Google DataForSEO avant la construction du client, exposition de devis hors ligne à partir des prix fournis, prise en compte de la profondeur SERP et des frais d'opérateurs de recherche, et application de plafonds connus en USD par appel avant tout transport. Extension des opérations bornées d'index de backlinks, et journalisation des coûts manquants ou des formes de réponse mal formées comme reçus incertains. Les limites de devise par projet et par mois restent en attente d'une décision du propriétaire. - Fusion des preuves explicites de source et d'import de backlinks dans des instantanés d'historique local privés, avec toutes les observations de jetons rel, les ancres, les domaines référents, les filtres et des signaux transparents de revue de spam. Ajout de routes CLI/MCP de profil et d'export de désaveu relu, sans soumission automatique. - Ajout de notices de revue des jetons rel mixtes et des mentions de sponsoring sortantes, issues des preuves natives conservées, en préservant le contexte indisponible, des comptes nuls pour les populations HTML entièrement non analysées, et les classes sponsored, ugc et nofollow dans les rapports et les contrôles de donneurs de liens, sans modifier le schéma figé des scans conservés.

    #1310 (ticket sur GitHub)
  • ModifiéFonctionneLes contrôles DOM et de doublons natifs lisent désormais le document conservé de chaque#1307

    page par URL exacte…

    Les contrôles DOM et de doublons natifs lisent désormais le document conservé sélectionné de chaque page par URL exacte, avec traçabilité vérifiée de la réponse et du corps. Les retenues désactivées, corps manquants, invalides ou dépassant le budget restent des omissions explicites ; les constats partiels portent une couverture. Les empreintes exactes de la zone de contenu et les constats SimHash/LSH bornés persistent dans l'audit natif, sans exiger de répertoire HTML SF. Les bandes LSH à seuil adaptatif préservent le rappel des paires qualifiantes tout en réduisant les gros seaux de candidats. L'épuisement du budget d'analyse proche de la similarité n'écarte pas les constats de hachage exact. - Les audits SF exécutent facultativement une similarité sémantique et une revue titre/H1 contre le corps conservé, avec un adaptateur local fourni explicitement ou des embeddings déclarés. Aucun modèle ni fournisseur n'est choisi automatiquement. L'identité de l'adaptateur, les empreintes source, les scores, les limites et les omissions accompagnent les candidats à la revue. La similarité sémantique n'affirme ni contenu dupliqué, ni pertinence de requête, ni cannibalisation. Les deux lignes de couverture SF sémantique restent des lacunes tant qu'un adaptateur réel n'est pas sélectionné et validé. L'autorisation d'un fournisseur externe exige le booléen littéral true ; des chaînes ou des entiers jugés vrais n'autorisent jamais un appel d'embedding.

    #1307 (ticket sur GitHub)
  • ModifiéFonctionneLes références de la boîte de réception acceptent les identifiants d'objectif#1314

    (inbox:<uuid>), afin qu'une note puisse citer l'objectif concerné. - Les éléments de checklist jamais tentés et manuels passent à l'état not_run au lieu de review ; seule une tentative en attente de décision reste en review. - Le modèle de lecture Issues (preuves observe des constats) rapporte les comptes par contrôle (by_check) et un next_offset après les 20 premiers constats ; findings_page pagine le reste.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneScans de projet planifiés (#1322, noyau) : schedule.json dans chaque dossier de projet#1322

    contient la planification propre à ce site…

    Scans de projet planifiés (#1322, noyau) : schedule.json dans chaque dossier de projet contient la planification indépendante de ce site (jours de semaine et/ou jours du mois, fenêtre horaire dans le fuseau du site, activation ou désactivation, mode de crawl spider/sitemap/list, budgets d'exécution par URL et par requête, délai de politesse, user agent, et état de reprise par tranche relatif au projet). Le projet propriétaire peut inclure les concurrents liés, chacun avec sa propre cadence et sa propre politique de scan. Les réglages se modifient via schedule-set / seo_schedule_set avec expected_revision ; schedule-show indique l'état d'échéance du principal et des concurrents liés, ainsi que la prochaine exécution. schedule-run-due est un point d'entrée sans interface qui n'exécute que les scans indépendamment dus, conserve des verrous à portée de processus jusqu'à la fin de chaque exécution, enregistre l'état d'annulation avant de la relancer, et journalise les résultats ou le chevauchement des concurrents dans chaque projet concerné. schedule-install et schedule-uninstall n'écrivent ni ne suppriment un plist launchd, une ligne cron ou une commande du Planificateur de tâches que lorsqu'ils sont appelés explicitement. - User agents de crawl : préréglages (spiderhead, googlebot, googlebot-desktop, googlebot-smartphone, bingbot, yandexbot, yandexmobilebot, baiduspider, duckduckbot, applebot, gptbot, claudebot, perplexitybot, et navigateurs de bureau et mobiles), ou une chaîne personnalisée. La valeur par défaut est désormais SpiderHeadBot/<version> (+https://github.com/PavloSEO/spiderhead), et la correspondance du groupe robots.txt utilise la même identité. Les sites qui correspondaient à l'ancien groupe robots SEOHEAD-Tools doivent nommer SpiderHeadBot dans leurs règles.

    #1322 (ticket sur GitHub)
  • ModifiéFonctionneworkflow-start n'a besoin que d'un objectif propriétaire accepté : --goal-id (ou#1314

    context.goal_id) suffit. Le prompt enregistré est par défaut skill:workflow/full-audit-v1, et la tâche de checklist par défaut est celle créée à l'acceptation de l'objectif (custom:goal-<entry>). Les refus nomment la commande propriétaire qui corrige le lien manquant. Les options sont documentées dans seohead workflow-start --help. - Les populations de checklist acceptent des objets partiels : seuls kind et source sont obligatoires, les autres clés prennent une valeur non définie par défaut. Une population refusée nomme ses clés manquantes ou inconnues. - Les crawls natifs de projet se rabattent sur /sitemap.xml de l'origine lorsque robots.txt ne déclare aucun sitemap. Un repli absent est enregistré comme incomplet, mais n'interrompt pas le crawl.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLes espaces de travail concurrents conservent l'URL telle que saisie : un crawl#1314

    concurrent part de son URL www et non de l'hôte nu, et un crawl d'une URL concurrente ne marque plus les éléments de checklist du propriétaire ; le résultat n'est enregistré que dans l'espace de travail du concurrent. L'ouverture d'un projet dont l'espace de travail concurrent est endommagé signale ce concurrent comme indisponible, au lieu d'échouer.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLa couverture de checklist de projet est désormais liée aux rapports audit.v2 en flux :

    report-build --project et audit-workflow --action report attachent l'instantané de checklist aux sorties xlsx, docx, csv, md et PDF, au lieu de produire un rapport non lié. Un scan arrêté par son budget d'URL (stopped_by_budget) est accepté comme dernier scan audité du projet, et son rapport indique la portée limitée. report-build --input accepte la clé format. report-build --project --format json sur un audit en flux est refusé avec une explication, car le JSON est écrit tel quel et ne peut pas porter l'instantané de checklist.

Prévu

Feuille de route

108 ouverts

Jalons ouverts sur GitHub. Chaque ligne est un ticket ouvert : travail prévu, pas encore livré.

Les bases du bureau

10 sur 14 fermés

D’abord une app de bureau qui marche : blocages, taille 800×600, onglets morts, états honnêtes (vague 1 du plan)

  • AjoutéPrévuDesktop : parcours complet sur un projet réel (visuel, scans, problèmes, exports, outils)#1358 (ticket sur GitHub)
  • CorrigéPrévuDesktop : onglets inactifs, actions désactivées et écrans provisoires#1347 (ticket sur GitHub)
  • AjoutéPrévuWindows : le crawl natif, le journal de projet et le build Desktop échouent ; Desktop#1345

    multiplie les fenêtres vides et est inutilisable en 4K

    #1345 (ticket sur GitHub)

Parité du bureau

19 sur 34 fermés

Ergonomie au niveau attendu : onglets, colonnes par filtre, détail depuis la vue d’ensemble, mise en page conservée (épique #1522)

Moteur d’exploration

9 sur 51 fermés

Politesse et règles robots, relances, budgets, découverte, stockage à grande échelle, cycle de vie du scan (épique #1520)

  • AjoutéPrévuPoint de départ du crawl depuis un Google Sheet#1527 (ticket sur GitHub)
  • AjoutéPrévuCollecter les annotations canonical et de pagination transmises dans l'en-tête de réponse#1517

    HTTP Link, avec leur origine de déclaration

    #1517 (ticket sur GitHub)
  • AjoutéPrévuPiloter un crawl en cours : restriction du périmètre à la volée et injection d'URL#1485 (ticket sur GitHub)
  • AjoutéPrévuCrawl optionnel des routes à identifiant de fragment#1482 (ticket sur GitHub)
  • AjoutéPrévuPlafond automatique du nombre de pages rendues en parallèle selon la mémoire disponible#1480 (ticket sur GitHub)
  • AjoutéPrévuÉchec de rendu comme résultat d'URL distinct#1479 (ticket sur GitHub)
  • AjoutéPrévuInclure le contenu du shadow DOM et des iframes dans la capture rendue#1477 (ticket sur GitHub)
  • AjoutéPrévuCapturer les messages de la console du navigateur pour chaque URL rendue#1475 (ticket sur GitHub)
  • AjoutéPrévuGarde-fou d'espace disque libre pour le stockage des scans#1474 (ticket sur GitHub)
  • AjoutéPrévuMode de compatibilité pour les anciens serveurs TLS#1473 (ticket sur GitHub)
  • AjoutéPrévuMotif d'échec réseau classifié par URL#1472 (ticket sur GitHub)
  • AjoutéPrévuEnregistrer la source de découverte de chaque URL crawlée#1471 (ticket sur GitHub)
  • AjoutéPrévuRésoudre les liens relatifs par rapport à l'URL de base du document#1470 (ticket sur GitHub)
  • AjoutéPrévuOrdre de visite stable pour des crawls reproductibles#1469 (ticket sur GitHub)
  • AjoutéPrévuDépenser le budget de crawl en commençant par les pages les moins profondes#1468 (ticket sur GitHub)
  • AjoutéPrévuLa profondeur de clic reflète le chemin de découverte le moins profond#1467 (ticket sur GitHub)
  • AjoutéPrévuNormalisation structurelle des URL avant la déduplication du crawl#1466 (ticket sur GitHub)
  • AjoutéPrévuRécupérer robots.txt une seule fois par origine en cas de concurrence#1465 (ticket sur GitHub)
  • AjoutéPrévuRespecter Retry-After et ralentir face aux réponses de limitation#1463 (ticket sur GitHub)
  • AjoutéPrévuAuthentification par formulaire web pour les crawls rendus#1447 (ticket sur GitHub)
  • AjoutéPrévuNouvelle tentative bornée et optionnelle sur les réponses 5xx#1446 (ticket sur GitHub)
  • AjoutéPrévuBudgets de crawl étendus : profondeur de dossier, par sous-domaine, par niveau de#1445

    profondeur, par motif de chemin, nombre max de liens par page

    #1445 (ticket sur GitHub)
  • AjoutéPrévuOptions de génération de sitemap : priority, changefreq, PDF, images CDN, fichiers par#1444

    segment

    #1444 (ticket sur GitHub)
  • AjoutéPrévuPréréglages d'export réutilisables#1443 (ticket sur GitHub)
  • AjoutéPrévuCertificats d'autorité personnalisés de confiance pour le trafic crawlé#1442 (ticket sur GitHub)
  • AjoutéPrévuTraiter les noms d'hôte de CDN et de miroirs comme périmètre interne#1441 (ticket sur GitHub)
  • AjoutéPrévuMoteur de réécriture d'URL pour le périmètre du crawl#1440 (ticket sur GitHub)
  • AjoutéPrévuRemplacement personnalisé de robots.txt pour un crawl#1439 (ticket sur GitHub)
  • AjoutéPrévuPolitique d'acceptation des cookies configurable pour les crawls#1438 (ticket sur GitHub)
  • AjoutéPrévuExport d'archive hors ligne du site web#1437 (ticket sur GitHub)
  • AjoutéPrévuDécouverte à partir des cibles d'annotations (canonical, hreflang, AMP, meta refresh,#1436

    iframes)

    #1436 (ticket sur GitHub)
  • AjoutéPrévuCrawler et auditer les éléments média (video, audio, source)#1435 (ticket sur GitHub)
  • AjoutéPrévuDétecter et signaler les liens internes non crawlables#1434 (ticket sur GitHub)
  • AjoutéPrévuCollecte Lighthouse locale sur un échantillon d'URL rendues#1430 (ticket sur GitHub)
  • AjoutéPrévucontrol/rate-and-load : distinguer les 5xx dus au débit des 403/429 de protection#1366

    anti-bot à l'étape « avant d'accuser le site »

    #1366 (ticket sur GitHub)
  • AjoutéPrévurobots-check signale « pas de robots.txt (crawl autorisé) » quand robots.txt renvoie un#1364

    403 d'un WAF

    #1364 (ticket sur GitHub)
  • AjoutéPrévuLe client HTTP reçoit un 403 à chaque requête vers une boutique Shopify derrière#1363

    Cloudflare qui répond 200 à curl

    #1363 (ticket sur GitHub)
  • AjoutéPrévuLive crawl speed control: change rate and threads during a running scan#1360 (ticket sur GitHub)
  • AjoutéPrévuCore : aspérités relevées lors de l'intégration de projets réels (concurrents, logs,#1359

    limites de crawl, archive)

    #1359 (ticket sur GitHub)

Analyse et champs de données

10 sur 64 fermés

Lisibilité, vecteurs et sémantique, champs par URL, couverture des contrôles, synthèses (épique #1521)

  • AjoutéPrévuRegrouper plusieurs exports de tableur dans un seul classeur#1528 (ticket sur GitHub)
  • AjoutéPrévuConstats d'accessibilité avec choix du niveau WCAG et taxonomie de gravité par impact#1526 (ticket sur GitHub)
  • AjoutéPrévuEnregistrer l'attribut SameSite de chaque cookie observé#1519 (ticket sur GitHub)
  • AjoutéPrévuExtraction personnalisée multi-moteurs avec statut de validation#1513 (ticket sur GitHub)
  • AjoutéPrévuBloc de synthèse de la population crawlée#1512 (ticket sur GitHub)
  • AjoutéPrévuRègles de recalcul en direct des statistiques d'audit#1511 (ticket sur GitHub)
  • AjoutéPrévuScore de lien interne comme métrique optionnelle après crawl#1510 (ticket sur GitHub)
  • AjoutéPrévuExport du tableau d'audit conforme au mode de comparaison affiché#1509 (ticket sur GitHub)
  • AjoutéPrévuDétail de l'audit par segment avec graphiques de gravité#1508 (ticket sur GitHub)
  • AjoutéPrévuVolet de recommandations par constat avec copie et liens externes#1507 (ticket sur GitHub)
  • AjoutéPrévuDelta des constats entre deux scans avec coloration des améliorations#1506 (ticket sur GitHub)
  • AjoutéPrévuPart du corpus en pourcentage pour chaque constat#1505 (ticket sur GitHub)
  • AjoutéPrévuTri par défaut des constats d'audit par priorité#1504 (ticket sur GitHub)
  • AjoutéPrévuCompteurs de synthèse de l'audit avec filtre par type#1503 (ticket sur GitHub)
  • AjoutéPrévuTaxonomie de gravité à double axe pour les constats d'audit#1502 (ticket sur GitHub)
  • AjoutéPrévuErreurs de console JavaScript comme constats de page#1487 (ticket sur GitHub)
  • AjoutéPrévuValider les réponses des cibles de pagination#1458 (ticket sur GitHub)
  • AjoutéPrévuAgrégation de l'usage de chaque image sur l'ensemble des pages#1457 (ticket sur GitHub)
  • AjoutéPrévuAfficher la règle robots.txt correspondante pour chaque URL bloquée#1456 (ticket sur GitHub)
  • AjoutéPrévuExtraire les annotations hreflang des en-têtes HTTP Link et des sitemaps XML#1455 (ticket sur GitHub)
  • AjoutéPrévuPourcentage de similarité des paires de quasi-doublons et différences surlignées#1454 (ticket sur GitHub)
  • AjoutéPrévuAudit de l'inventaire des cookies avec synthèse première partie / tierce partie#1453 (ticket sur GitHub)
  • AjoutéPrévuSuivre les meta keywords en double et multiples sur les pages#1452 (ticket sur GitHub)
  • AjoutéPrévuCollecter les images d'arrière-plan CSS comme éléments de preuve d'images#1451 (ticket sur GitHub)
  • AjoutéPrévuConstats pour les chaînes de redirections qui se terminent par une erreur client ou#1450

    serveur

    #1450 (ticket sur GitHub)
  • AjoutéPrévuPopulation d'analyse configurable pour l'évaluation des doublons et des problèmes#1449 (ticket sur GitHub)
  • AjoutéPrévuExtraire et auditer les propriétés et les liens des documents PDF#1448 (ticket sur GitHub)
  • AjoutéPrévuEstimation de l'empreinte carbone d'une page#1433 (ticket sur GitHub)
  • AjoutéPrévuRecherche vectorielle sur le corpus conservé#1432 (ticket sur GitHub)
  • AjoutéPrévuAnalyse de fréquence des n-grammes sur le contenu crawlé#1431 (ticket sur GitHub)
  • AjoutéPrévuLiens internes et texte du corps présents uniquement après rendu comme constats à part#1429

    entière

    #1429 (ticket sur GitHub)
  • AjoutéPrévuAjouter des contrôles pour les fichiers JS et CSS externes cassés ou interdits par#1427

    robots.txt

    #1427 (ticket sur GitHub)
  • AjoutéPrévuAjouter un contrôle pour un nombre excessif de fichiers JS et CSS par page#1426 (ticket sur GitHub)
  • AjoutéPrévuAjouter un contrôle de discordance entre la langue hreflang et le lang du html#1425 (ticket sur GitHub)
  • AjoutéPrévuAjouter un contrôle des valeurs href malformées#1424 (ticket sur GitHub)
  • AjoutéPrévuAjouter aux scans les constats sur les variantes www et http de la page d'accueil#1423 (ticket sur GitHub)
  • AjoutéPrévuAjouter aux scans les constats sur la présence et le format de llms.txt#1422 (ticket sur GitHub)
  • AjoutéPrévuSignaler un sitemap.xml invalide comme constat de scan#1420 (ticket sur GitHub)
  • AjoutéPrévuSignaler un robots.txt invalide comme constat de scan#1419 (ticket sur GitHub)
  • AjoutéPrévuAjouter une sonde TLS : expiration du certificat, nom d'hôte non concordant, version du#1418

    protocole, chiffrements faibles

    #1418 (ticket sur GitHub)
  • AjoutéPrévuAjouter un contrôle des ressources non HTML liées comme des liens de page ordinaires#1417 (ticket sur GitHub)
  • AjoutéPrévuAjouter un contrôle des pages ayant un seul lien interne entrant#1416 (ticket sur GitHub)
  • AjoutéPrévuConserver les liens externes avec rel et ajouter EXTERNAL_NOFOLLOW#1415 (ticket sur GitHub)
  • CorrigéPrévuLes en-têtes de sécurité et HSTS ne sont jugés que sur la réponse finale ; les étapes de#1414

    redirection et l'hôte www ne sont jamais vérifiés

    #1414 (ticket sur GitHub)
  • CorrigéPrévuLes règles de rich result SoftwareApplication sont trop laxistes ; vérifier que les#1413

    erreurs de données structurées de la page d'accueil remontent

    #1413 (ticket sur GitHub)
  • CorrigéPrévuLOW_TEXT_RATIO se déclenche sur presque toutes les pages ; recalibrer la mesure et le#1412

    seuil

    #1412 (ticket sur GitHub)
  • CorrigéPrévuLes constats groupés affichent un nombre de 1 et sont absents des recherches de constats#1411

    par URL

    #1411 (ticket sur GitHub)
  • AjoutéPrévusite-audit émet des constats au niveau de la page pour une réponse en erreur au lieu de#1365

    marquer la page comme non auditée

    #1365 (ticket sur GitHub)

Projets et workflows

8 sur 10 fermés

Workflows du propriétaire : tâches, exports, rapports planifiés et leur envoi (épique #1314)

Changement de nom

0 sur 1 fermés

Renommage seohead → spiderhead : CLI, paquet, environnement, documentation (#1523)

  • AjoutéPrévuRenommer le binaire CLI, le package et le préfixe d'environnement de seohead en spiderhead#1523 (ticket sur GitHub)

Interfaces CLI et MCP

7 sur 12 fermés

Messages d’erreur clairs, vraie aide, sorties de lecture bornées, transports MCP (épiques #1410 #1421)

  • AjoutéPrévuServeur MCP comme mode CLI de premier rang avec transports stdio et HTTP streamable#1525 (ticket sur GitHub)
  • CorrigéPrévuAfficher une vraie sous-aide pour « seohead sf » au lieu d'un simple relais d'arguments#1406 (ticket sur GitHub)

Couche IA

0 sur 1 fermés

Cibles de prompt par élément SEO au-dessus de seo_ai_column, indépendantes du fournisseur (#1524)

  • AjoutéPrévuAnalyse de pages assistée par IA avec cibles de prompt configurables sur les données de#1524

    crawl

    #1524 (ticket sur GitHub)

Qualité du code

0 sur 2 fermés

Découpage en modules des fichiers géants et sens des dépendances (#1514 #1515)

  • AjoutéPrévuSens des dépendances : supprimer les inversions d'import du cœur vers les fonctionnalités#1515 (ticket sur GitHub)
  • AjoutéPrévuDécouper les modules d'adaptateur et de moteur trop volumineux en unités cohérentes#1514 (ticket sur GitHub)

Distribution: installers & one-command install

0 sur 2 fermés

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.

Version

3.1.0

Première version étiquetée après le renommage de SEOHEAD Tools11 octobre 2026
455 entrées · Première version étiquetée après le renommage de SEOHEAD Tools138 ajouté275 modifié42 corrigé

11 octobre 2026

5 ajouté54 modifié2 corrigé
  • ModifiéFonctionneReconstruction des paramètres de projet Planification et Crawl avec des composants natifs#1323

    partagés (canvas), polices Roboto et Material Symbols hors ligne, et mise en page en colonne unique à 800 px.

    #1323 (ticket sur GitHub)
  • ModifiéFonctionneL'interface de l'application reste en anglais, les commandes de planification et les#1323

    contrats de documents existants sont conservés, et seules les données de planification adossées au noyau sont affichées.

    #1323 (ticket sur GitHub)
  • ModifiéFonctionnePréserver les identités et alias des espaces de travail pendant que les paramètres du#1323

    projet sont ouverts ; empêcher les enregistrements en double pendant que le noyau répond.

    #1323 (ticket sur GitHub)
  • ModifiéFonctionneLes paramètres de projet du bureau reçoivent un onglet Planification (jours de semaine,#1322

    jours du mois, fenêtre d'exécution, fuseau horaire, concurrents) et un onglet Crawl (mode de crawl, préréglage User-Agent ou chaîne personnalisée, pause entre requêtes, budget d'URL, SpiderHeadBot ou un user agent personnalisé). Les deux lisent et écrivent le projet via le noyau, et l'aperçu du projet affiche la prochaine et la dernière exécution planifiée. Un mode --tray exécute les scans dus du noyau et ne maintient le Mac éveillé que pendant qu'un scan tourne.

    #1322 (ticket sur GitHub)
  • ModifiéFonctionneScans de projet planifiés (#1322, core) : schedule.json dans le dossier du projet#1322

    contient la planification (jours de la semaine et/ou jours du mois, plage horaire dans le fuseau du site, activation ou désactivation, concurrents, mode de crawl spider/sitemap/list, budgets d'URL et de requêtes par exécution, délai de politesse, et mode par tranches qui reprend le crawl partiel précédent). Il se modifie avec schedule-set / seo_schedule_set en passant expected_revision, et schedule-show affiche la dernière exécution et la prochaine fenêtre due. schedule-run-due est un point d'entrée sans interface qui ne lance que les scans dus, refuse les chevauchements grâce à un bail et consigne chaque décision dans le journal du projet. schedule-install et schedule-uninstall n'écrivent ou ne suppriment un plist launchd, une ligne cron ou une commande du Planificateur de tâches que lorsqu'on les appelle explicitement.

    #1322 (ticket sur GitHub)
  • ModifiéFonctionneUser-agents de crawl (#1322) : préréglages (spiderhead, googlebot,#1322

    googlebot-desktop, googlebot-smartphone, bingbot, yandexbot, yandexmobilebot, baiduspider, duckduckbot, applebot, gptbot, claudebot, perplexitybot, ainsi que des navigateurs de bureau et mobiles) ou une chaîne personnalisée. Par défaut, c'est désormais SpiderHeadBot/<version> (+https://github.com/PavloSEO/spiderhead), et la correspondance des groupes de robots.txt utilise la même identité. Les sites qui correspondaient à l'ancien groupe robots SEOHEAD-Tools doivent désigner SpiderHeadBot dans leurs règles.

    #1322 (ticket sur GitHub)
  • ModifiéFonctionneUn crawl de projet enregistré marque désormais les éléments automatiques de la checklist#1314

    qu'il a mesurés.

    Chaque élément de contrôle activé aboutit à l'un de trois résultats : succeeded lorsque l'audit enregistré a exécuté le contrôle, avec le scan comme preuve ; unavailable lorsque le crawl l'a ignoré ou désactivé, avec la raison du crawl conservée ; ou unmeasured lorsque l'audit ne mentionne pas du tout le contrôle. Un élément non mesuré conserve son enregistrement précédent et figure par son nom dans checklist_evidence : il ne compte donc jamais comme 0. Un crawl en échec ou interrompu marque ses contrôles automatiques comme failed, avec la raison de l'échec. Le même chemin d'enregistrement sert désormais le flux prepare, qui disposait de sa propre copie de la boucle. Un projet dont la checklist n'est pas initialisée est ignoré, avec une raison indiquée.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLes espaces de travail concurrents conservent l'URL telle qu'elle a été saisie : un crawl#1314

    de concurrent démarre depuis son URL www au lieu de l'hôte nu, et un crawl d'une URL concurrente ne marque plus les éléments de checklist du propriétaire ; le résultat n'est enregistré que dans l'espace de travail du concurrent. Ouvrir un projet dont l'espace de travail concurrent est endommagé signale ce concurrent comme indisponible au lieu d'échouer.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLes candidats concurrents peuvent être enregistrés, listés et supprimés depuis la CLI#1314

    (project-competitors-add, project-competitors-list, project-competitors-remove) et via les outils MCP correspondants seo_project_competitors_*. Chaque candidat conserve l'URL telle qu'elle a été saisie, y compris un hôte www, et les hôtes avec ou sans www sont considérés comme le même site lors des contrôles de doublons. Un concurrent avec un hôte www ne bloque plus la préparation et ne fait plus échouer project-observe.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionne--max-urls est désormais le budget de pages du crawl : un budget de pages explicite#1314

    complète les budgets de requêtes et de temps non définis (3 requêtes et 2 secondes par page), de sorte que les crawls de 50 à 300 pages sont admis sans approve_large_crawl. Les budgets supérieurs aux seuils du projet restent refusés.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneUn arrêt volontaire par budget d'URL est enregistré comme capture terminée avec#1314

    finish_reason…

    Un arrêt volontaire par budget d'URL est enregistré comme capture terminée, avec finish_reason stopped_by_budget et une heure finished_at, au lieu de interrupted sans heure de fin. Ses URL en file d'attente restent disponibles pour une reprise.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLes URL des concurrents conservent l'hôte tel qu'il a été saisi (par exemple www.#1314

    reste), au lieu d'être stockées sans lui.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneL'application de bureau ajoute des sites concurrents depuis le presse-papiers ou un par#1314

    un via le core, définit un plafond d'URL par site et lance leurs scans en parallèle. Un concurrent n'apparaît comme scanné qu'après un scan conservé et terminé.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLes scans natifs mesurent HSTS, le contenu mixte et les données structurées à partir de#1314

    leurs propres preuves conservées, de sorte qu'un export SF absent ou périmé ne les signale plus comme manquants ; duplicate-check marque une exécution sans aucune paire comparée comme non mesurée ; les constats de gabarit à l'échelle du site (même titre de gabarit, faible ratio de texte) forment un seul constat avec un nombre de pages (#1314).

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneAccepter un objectif du propriétaire n'ajoute que la tâche de checklist de cet objectif.#1314

    Il ne réconcilie plus tout le catalogue intégré dans coverage.json ; les lignes intégrées sont ajoutées à la demande, lorsqu'on les touche.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneUne checklist occupée nomme le détenteur actif du verrou (par exemple un crawl natif en#1314

    cours et son pid) au lieu de parler d'un verrou résiduel.

    Le verrou enregistre le pid de son écrivain ; un verrou sans détenteur actif reste signalé comme résiduel.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneUne exécution de workflow bloquée par une étape en échec, indisponible, ignorée ou#1314

    interrompue reste reprenable, et une étape en attente ultérieure peut être enregistrée au-delà d'une étape qui n'a pas réussi. Les étapes doivent toujours être enregistrées dans l'ordre d'enregistrement, et une exécution interrompue refuse toujours les étapes suivantes.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneUn examen enregistré par un agent ne rend plus un élément manuel ou livrable complet côté#1314

    propriétaire.

    L'élément reste en attente de la validation du propriétaire ou d'un relecteur qui ne soit pas un agent.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLes références de l'inbox acceptent désormais les identifiants d'objectif#1314

    (inbox:<uuid>), afin qu'une note puisse citer l'objectif qu'elle concerne.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLes éléments de checklist jamais tentés et manuels affichent l'état not_run au lieu de#1314

    review ; seule une tentative en attente de décision reste en review.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLe modèle de lecture Issues (preuves de constats observe) indique les décomptes par#1314

    contrôle (by_check) et un next_offset après les 20 premiers constats ; findings_page permet de parcourir les suivants.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneContrôles de crawl natifs (#1314) : la taille des images (IMG_OVER_KB) est désormais#1314

    mesurée à partir des téléchargements d'images du crawl lui-même…

    Contrôles de crawl natifs (#1314) : la taille des images (IMG_OVER_KB) est désormais mesurée à partir des téléchargements d'images propres au crawl, et le statut du sitemap (SITEMAP_URL_4XX_5XX, SITEMAP_URL_3XX, SITEMAP_URL_NON_INDEXABLE) à partir de la récupération, par le crawl, de chaque URL listée dans le sitemap. Une URL listée que le crawl n'a jamais demandée est comptée comme non mesurée, jamais comme saine. IMG_MISSING_ALT, IMG_MISSING_DIMENSIONS et HREFLANG_ERROR indiquent désormais, sur un scan natif, que le crawl ne les mesure pas selon la définition de l'export SF, au lieu de renvoyer vers un filtre SF. Un hreflang manquant ou un contenu mixte sur un scan natif est signalé comme non mesuré par le crawl natif, et non comme un export manquant.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneJournal de projet (#1314) : chaque événement du projet est désormais aussi écrit sous#1314

    forme d'une puce dans log.md, et le core enregistre des entrées automatiques pour les crawls terminés (scans), les rapports de projet générés et les tentatives de checklist (agent). Les entrées vont dans events.jsonl et sont lues par project-event-page ; les déclencheurs automatiques ne font jamais échouer le crawl, le rapport ou l'étape de checklist qu'ils décrivent. project-event-append et seo_project_event_append conservent leur interface et ajoutent la ligne dans log.md.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLe crawl natif stocke désormais les en-têtes de sécurité lus par les contrôles#1314

    (Strict-Transport-Security, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy). Auparavant, ils étaient écartés à la capture : un site qui envoyait HSTS était signalé comme ne l'ayant pas. Les en-têtes Set-Cookie ne conservent que leurs attributs (secure, httponly, samesite=), jamais le nom ni la valeur du cookie. Un en-tête de sécurité envoyé plusieurs fois sur la même page est signalé comme DUPLICATE_SECURITY_HEADER.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneworkflow-start n'exige qu'un objectif accepté par le propriétaire : --goal-id (ou#1314

    context.goal_id) suffit. Le prompt enregistré est skill:workflow/full-audit-v1 par défaut, et la tâche de checklist est, par défaut, celle qui accompagne l'objectif accepté (custom:goal-<entry>). Les refus indiquent la commande propriétaire qui corrige le lien manquant. Les options sont documentées dans seohead workflow-start --help.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLes populations de checklist acceptent des objets partiels : seuls kind et source#1314

    sont obligatoires, et les autres clés sont par défaut non définies. Une population refusée indique ses clés manquantes ou inconnues.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLes crawls natifs de projet se rabattent sur /sitemap.xml de l'origine lorsque#1314

    robots.txt ne déclare aucun sitemap. Un repli absent est consigné comme incomplet, mais n'interrompt pas le crawl.

    #1314 (ticket sur GitHub)
  • ModifiéFonctionneLes journaux serveur conservent désormais les totaux exacts d'IP de bots sur disque au#1311

    lieu d'un échantillon plafonné, avec…

    Les journaux serveur conservent désormais les totaux exacts d'IP de bots stockés sur disque au lieu d'un échantillon plafonné, avec des enregistrements par IP bornés, des visites, la dernière visite et des filtres par sous-réseau. La vérification DNS explicite contrôle séparément chaque IP sélectionnée, enregistre les preuves PTR et de résolution directe, prend en charge l'IPv6, et conserve les résultats indisponibles ou hors délai comme non vérifiés. Les caches locaux expirent au bout d'une heure ; les lectures ne déclenchent jamais de DNS.

    #1311 (ticket sur GitHub)
  • AjoutéFonctionneAjout de l'import local des journaux de projet, du résumé paginé, des preuves de bots et#1311

    des jointures avec les scans natifs, via les gestionnaires CLI/MCP partagés. Les artefacts de journaux séparés conservent les partitions par date ainsi que la couverture et la provenance des sources, sans modifier les schémas figés des scans. Des preuves manquantes ou incomplètes retiennent toute conclusion d'absence. Les écrans de journaux de l'application de bureau restent un chantier distinct.

    #1311 (ticket sur GitHub)
  • ModifiéFonctionneContrôle des appels de production Google DataForSEO avant la construction du client,#1310

    devis hors ligne à partir des prix fournis, prise en compte de la profondeur SERP et des frais des opérateurs de recherche, et application des plafonds USD connus par appel avant tout transport. Élargissement des opérations bornées sur l'index des backlinks ; les coûts manquants et les formes de réponse mal formées sont consignés dans le journal comme reçus incertains. Les plafonds en devise par projet et par mois restent en attente d'une décision du propriétaire.

    #1310 (ticket sur GitHub)
  • ModifiéFonctionneFusion des preuves explicites de source et d'import de backlinks dans les instantanés#1310

    d'historique locaux privés, avec les observations complètes des jetons rel, les ancres, les domaines référents, les filtres et des signaux transparents de revue de spam. Ajout de commandes CLI et d'outils MCP pour le profil et l'export de désaveu relu, sans aucune soumission automatique.

    #1310 (ticket sur GitHub)
  • AjoutéFonctionneAjout de notices de revue pour les jetons rel mixtes et les mentions sponsorisées#1310

    sortantes, à partir des preuves natives conservées. Le contexte indisponible est préservé, les décomptes nuls servent aux populations HTML entièrement non analysées, et les classes sponsored, ugc et nofollow apparaissent dans les rapports et les contrôles des sites donneurs, sans modifier le schéma figé des scans conservés.

    #1310 (ticket sur GitHub)
  • ModifiéFonctionneLes contrôles DOM et de doublons natifs lisent désormais le document conservé de chaque#1307

    page par URL exacte, avec une traçabilité vérifiée de la réponse et du corps. Une conservation désactivée, des corps manquants, invalides ou au-delà du budget restent des omissions explicites ; les constats partiels portent leur couverture. Les empreintes exactes du contenu principal et les constats SimHash/LSH bornés sont persistés dans l'audit natif, sans répertoire HTML SF. Les bandes LSH adaptées au seuil préservent le rappel des paires qualifiantes tout en réduisant les compartiments candidats trop larges ; l'épuisement du budget d'analyse approchée ne supprime pas les constats par empreinte exacte.

    #1307 (ticket sur GitHub)
  • ModifiéFonctionneLes audits SF peuvent exécuter une similarité sémantique et une revue titre/H1 face au#1307

    corps conservé…

    Les audits SF peuvent exécuter, en option, une similarité sémantique et une revue titre/H1 par rapport au corps conservé, via un adaptateur local fourni explicitement ou des embeddings déclarés. Aucun modèle ni fournisseur n'est choisi automatiquement. L'identité de l'adaptateur, les empreintes des sources, les scores, les limites et les omissions accompagnent les candidats à la revue ; la similarité sémantique n'affirme ni contenu dupliqué, ni pertinence par rapport à la requête, ni cannibalisation. Les deux lignes de couverture sémantique SF restent des lacunes tant qu'aucun adaptateur réel n'est choisi et validé. L'autorisation d'un fournisseur externe exige le booléen littéral true ; des chaînes ou des entiers évalués comme vrais n'autorisent jamais un appel d'embedding.

    #1307 (ticket sur GitHub)
  • ModifiéFonctionneLes audits natifs conservés regroupent désormais les liens internes cassés par cible#1306

    observée, avec les preuves source et ancre, enregistrent les chaînes et boucles de redirections avec le statut de chaque saut, distinguent la recherche interne basée sur le chemin et les ancres vides, et exposent les résultats d'absence de réponse externes capturés. Les constats de cohérence du sitemap et de robots.txt utilisent l'appartenance et les preuves de réponse conservées, sans nouvelle requête en direct ; les preuves manquantes ou partielles restent explicites.

    #1306 (ticket sur GitHub)
  • AjoutéFonctionneAjout d'un graphe de liens borné pour les scans conservés, avec des filtres par position,#1306

    section et voisinage local, une agrégation par section et les changements d'arêtes d'un scan à l'autre. La réanalyse hors ligne complète les positions par lots dérivés reprenables, et signale les preuves non classées dans l'inspection des liens et l'état du scan, tout en préservant le schéma figé scan.v1.

    #1306 (ticket sur GitHub)
  • AjoutéFonctionneAjout de la génération locale de sitemap XML à partir des pages 200 conservées,#1306

    canoniques et indexables, avec la lastmod observée, des exclusions, la découpe par protocole, un index de sitemaps et un sitemap d'images facultatif. La CLI et le MCP partagent les mêmes implémentations ; la publication des fichiers exige un dossier local vide et neuf, et ne déploie jamais rien.

    #1306 (ticket sur GitHub)
  • ModifiéFonctionneConserve les cibles de découverte manquantes relevées au moment de la capture lorsque le#1306

    traitement ultérieur du sitemap ou des seeds ajoute l'URL au catalogue conservé. Les preuves non résolues ou exclues, déjà expliquées, restent immuables, tandis que les cibles connues revendiquées et les incohérences d'identité non nulles restent invalides.

    #1306 (ticket sur GitHub)
  • ModifiéFonctionneLa génération du sitemap d'images exclut les réponses de ressources non-200 connues, même#1306

    lorsque la ressource n'a pas été stockée comme page crawlée, et marque les réponses d'images non mesurées comme couverture partielle.

    #1306 (ticket sur GitHub)
  • ModifiéFonctionneConserve les attributs canonical et de pagination bruts comme contexte de document#1305

    versionné, sans modifier le SQL figé du scan. Les liens canoniques portant des attributs hreflang, lang, media ou type non pris en charge, des annotations mal formées ou des déclarations inter-hôtes et inter-protocoles produisent désormais des constats liés à leurs preuves ; les mots-clés de relation bien formés mais inconnus restent non classés.

    #1305 (ticket sur GitHub)
  • ModifiéFonctionneÉtend les sondes bornées de cible au même hôte à la pagination et conserve les#1305

    observations mesurées de noindex et de canonical. Les chaînes canoniques natives et les constats noindex et canonical/hreflang peuvent utiliser les sondes ; les anciennes sondes ne portant que le statut restent lisibles et non mesurées pour les directives HTML.

    #1305 (ticket sur GitHub)
  • ModifiéFonctionneJuge les chaînes de pagination natives opaques pour détecter les contradictions#1305

    réciproques explicites next/prev, en conservant les règles numérotées ou à pas et les états non jugés nommés. Sélectionne les URL des constats conservés, y compris les membres groupés, via scan-url-query, à l'aide de tables SQLite temporaires et d'un flux de preuves audit.v2.

    #1305 (ticket sur GitHub)
  • CorrigéFonctionneGarde non classés les jetons de relation Unicode inconnus et ceux contenant de la#1305

    ponctuation, normalise les autorités canoniques IDN et port par défaut équivalentes, et préserve les chemins exacts des cibles de pagination natives. Les jetons de page mixtes illisibles restent non jugés ; le défaut de pagination de la boutique est détecté même lorsque la page un ne contient aucun numéro dans son URL.

    #1305 (ticket sur GitHub)
  • ModifiéFonctionneRend les annotations next/prev déclarées de la fixture boutique, afin que sa vérité de#1305

    référence de pagination D41 soit réellement servie et validable par la capture native.

    Rend les annotations next/prev déclarées de la fixture boutique, afin que sa vérité de référence de pagination D41 soit réellement servie et puisse être validée par la capture native.

    #1305 (ticket sur GitHub)
  • ModifiéFonctionneConserve les preuves AMP statiques et d'accessibilité liées au document dans les lignes#1304

    de contexte de scan existantes, en préservant le SQL figé scan.v1. Les constats AMP structurels examinent la déclaration doctype d'origine, le head et le body, le charset UTF-8, le viewport, le script d'exécution et les déclarations de boilerplate ; les cibles AMP appariées sans marqueur de racine AMP sont identifiées séparément. Les règles complètes du validateur AMP restent indisponibles dans l'attente d'une décision de licence.

    #1304 (ticket sur GitHub)
  • ModifiéFonctionneLance les constats d'accessibilité sur la langue du document, les libellés de formulaire,#1304

    les alternatives d'images, les sauts de titres et le repère main. Les constats conservent des exemples bornés et les décomptes complets des occurrences. Le contraste calculé et les règles axe-core rendues restent non mesurés.

    #1304 (ticket sur GitHub)
  • ModifiéFonctionneValide les microdonnées Schema.org et les sujets et propriétés RDFa courants avec le#1304

    vocabulaire embarqué et les règles existantes de résultats enrichis. Les erreurs, avertissements et propriétés obligatoires manquantes conservés par URL deviennent des constats natifs. Les constructions RDFa non prises en charge constituent une preuve partielle explicite, et non un résultat de validation propre.

    #1304 (ticket sur GitHub)
  • ModifiéFonctionneSert les arbres JSON-LD analysés avec les erreurs de source, de position et de syntaxe de#1304

    chaque bloc dans…

    Sert les arbres JSON-LD analysés, avec pour chaque bloc les erreurs de source, de position et de syntaxe, dans scan-structured-blocks ; plafonne les arbres de propriétés larges et expose leur limite. Lit le dernier document pour une URL et une représentation demandées sans modifier son scan.

    #1304 (ticket sur GitHub)
  • ModifiéFonctionneConserve les preuves structurées partielles ou indisponibles sans masquer les erreurs#1304

    confirmées des blocs voisins.

    Résout les identités JSON-LD prises en charge par rapport à la même base de document que le balisage HTML, tout en préservant le JSON source ; rejette les blocs JSON scalaires ou vides comme graphes valides, et partage la sélection normalisée des balises JSON-LD en direct entre l'analyseur et les projections servies.

    #1304 (ticket sur GitHub)
  • ModifiéFonctionneLes audits natifs exposent désormais le balisage bloquant le rendu dans le head à partir#1303

    du HTML conservé complet…

    Les audits natifs exposent désormais le balisage bloquant le rendu dans le head, à partir du HTML conservé complet, sans modifier le schéma figé scan.v1. Les corps manquants, incomplets ou limités par le budget restent indisponibles. La détection existante des ressources du head et l'entrée d'extraction personnalisée SF sont réutilisées.

    #1303 (ticket sur GitHub)
  • AjoutéFonctionneAjoute des budgets configurables d'octets pour la navigation observée native et pour#1303

    chaque ressource individuelle, des signaux de livraison du cache et des polices, des heuristiques de minification et de scripts hérités, ainsi que les doublons exacts de scripts sur une même page, à partir des preuves scan.v2 conservées. Les données non téléchargées et les charges utiles d'exécution incomplètes restent explicites ; les déclarations responsives ne sont pas additionnées comme poids d'exécution. Les bornes inférieures HTML seules, les décomptes de couverture scalaires, les échantillons de polices et les résumés de sources restent explicites et bornés.

    #1303 (ticket sur GitHub)
  • ModifiéFonctionneCollecte une couverture JS/CSS Chromium précise et bornée lors des rendus demandés,#1303

    conserve les résumés d'usage en UTF-16 ainsi que les constats de dimensionnement d'images rendues, et les relit après réouverture ou réanalyse hors ligne. Les moteurs non pris en charge et les mesures manquantes ne deviennent jamais des résultats propres.

    #1303 (ticket sur GitHub)
  • ModifiéFonctionneAccepte le JSON Lighthouse par URL correspondant et borné pour la découverte du LCP, les#1303

    arbres de dépendances, les responsables des décalages de mise en page, la livraison des images, les reflows forcés et les constats d'exécution des scripts, avec la provenance de capture et les empreintes des entrées. Aucun processus Lighthouse, fournisseur payant ni inférence des CWV terrain n'est ajouté. Actualise le registre, la couverture SF et la documentation de référence générée.

    #1303 (ticket sur GitHub)
  • CorrigéFonctionneGarde les seuils additifs d'actifs hors de l'en-tête figé du scan natif et stocke leurs#1303

    valeurs exactes dans un contexte d'exécution validé et versionné. La reprise compare ces valeurs séparément, et la réanalyse hors ligne les restaure à partir des preuves conservées ; les anciens lecteurs légers peuvent toujours inspecter la forme inchangée de la configuration d'en-tête.

    #1303 (ticket sur GitHub)
  • ModifiéFonctionnerecord de la checklist accepte désormais un contrôle automatique réussi dont le scan

    conservé est un scan audit.v2 en flux ; auparavant, il échouait avec 'NoneType' object is not subscriptable, car l'audit se trouve dans le fichier compagnon et non dans la table héritée du scan. Les formats d'enregistrement acceptés sont documentés dans seohead project checklist-record --help, dans le schéma de l'outil MCP seo_project_checklist_record et dans docs/INPUTS.md.

  • ModifiéFonctionneExécute la suite complète du toolkit une seule fois sur Python 3.15 au lieu d'une matrice

    de versions plus anciennes, en conservant quatre groupes de tests vérifiés et la couverture combinée. La même version stable de Python sert à la CI et aux amorçages des builds de release.

  • ModifiéFonctionneLa liste Work de l'application de bureau lit chaque page de checklist (100 par requête)

    au lieu des 50 premières lignes ; Issues nomme chaque contrôle principal du registre au lieu d'afficher « Autre contrôle ».

  • ModifiéFonctionneLa vue Work de l'application de bureau lit toutes les pages de checklist, mais n'affiche

    le panneau des tâches du projet qu'une page à la fois, de sorte qu'une checklist de n'importe quelle taille n'échoue plus avec « at most 100 rows ». L'application ouvre le scan que laisse derrière elle un audit complet (le plus grand scan complet) lorsque le propriétaire n'en a pas choisi un, et la découverte du core vérifie aussi l'environnement propre de l'interpréteur de l'application (sys.prefix) avant le PATH.

  • ModifiéFonctionneConsolide les contrôles d'audit conservés et les améliorations natives de l'application

    de bureau.

    Préserve les réglages de budget de ressources sans modifier l'en-tête figé du scan, conserve une réanalyse hors ligne et une reprise sûres, et partage les composants natifs des réglages de projet, les tokens de thème et les polices embarquées. Retire les entrées de design privées de l'arborescence distribuée.

  • ModifiéFonctionneLie les revérifications de remédiation à la politique d'actifs effective validée tout en

    préservant l'en-tête de scan d'origine…

    Lie les revérifications de remédiation à la politique d'actifs effective validée, tout en préservant l'en-tête de scan d'origine et les octets source.

  • ModifiéFonctionneLa couverture de checklist de projet lie désormais les rapports audit.v2 en flux :

    report-build --project et audit-workflow --action report joignent l'instantané de checklist aux sorties xlsx, docx, csv, md et PDF, au lieu de produire un rapport non lié. Un scan arrêté par son budget d'URL (stopped_by_budget) est accepté comme dernier scan audité du projet, et son rapport indique la portée limitée. report-build --input accepte la clé format. report-build --project --format json sur un audit en flux est refusé avec une explication, car le JSON est écrit tel quel et ne peut pas porter l'instantané de checklist.

10 octobre 2026

16 ajouté51 modifié
  • ModifiéFonctionneLe moniteur de scan de l'application de bureau suit le tableau de conception ScanRun :#1203

    pourcentage réel à partir des compteurs fetched/found…

    Le moniteur de scan de l'application de bureau suit le tableau de conception ScanRun : pourcentage réel calculé à partir des compteurs fetched/found, barre de progression de 10 px, limite de débit du collecteur, et un emplacement réservé de 120 px, sans fausse donnée, pour le graphique de vitesse (l'historique des débits du core est suivi dans #1203).

    #1203 (ticket sur GitHub)
  • ModifiéFonctionnecheck_sample dans seohead/checks/custom_extract.py exécute les extracteurs CSS, XPath#1059

    et regex sur un seul document HTML enregistré, sans scan ni requête réseau. Chaque résultat porte ses valeurs et une reason pour un résultat vide (no_match, empty_html ou budget_exceeded), afin qu'une réponse vide ne soit jamais présentée comme un résultat propre (#1059). Il s'agit uniquement d'un appel du core ; aucun outil CLI ni MCP n'est encore enregistré, et la récupération d'une URL en direct est volontairement exclue.

    #1059 (ticket sur GitHub)
  • ModifiéFonctionneLe contrôle de séquence de pagination (PAGINATION_SEQUENCE_ERROR) juge désormais les#1057

    séries à pas : lorsqu'un pas couvre la plupart des pas d'une série, une rupture de ce pas est signalée (?page=1,3,5,8 rompt entre 5 et 8). Les schémas de décalage irréguliers et les séries sans numéro restent non jugés et sont nommés comme ignorés.

    #1057 (ticket sur GitHub)
  • AjoutéFonctionneNouveau contrôle de crawl INTERNAL_NOFOLLOW_OUTLINKS (notice) : indique chaque page#1052

    source qui…

    Nouveau contrôle de crawl INTERNAL_NOFOLLOW_OUTLINKS (notice) : il signale chaque page source qui porte des liens sortants internes en nofollow, avec leur nombre et un échantillon borné de destinations. Il comble l'écart au niveau de la page pour la ligne « Internal Nofollow Outlinks » de Screaming Frog, restée partial. Il s'exécute sur les crawls natifs et est ignoré par son nom lors des exécutions basées sur un export seul ou sur une liste d'URL.

    #1052 (ticket sur GitHub)
  • ModifiéFonctionneLe parseur lit les <link rel="alternate"> qualifiés par média, sans hreflang…#1051

    Le parseur lit les déclarations <link rel="alternate"> qualifiées par média, sans hreflang (une URL mobile distincte), et les range dans parse_html sous mobile_alternates (#1051). Le contrôle SF Mobile Alternate Link reste un écart : le contrôle qui compare la balise canonical de l'URL mobile n'est pas encore écrit.

    #1051 (ticket sur GitHub)
  • AjoutéFonctionneAjout du contrôle HREFLANG_UNLINKED_TARGET (warning) : une cible d'alternate hreflang#1050

    qu'aucun…

    Ajout du contrôle HREFLANG_UNLINKED_TARGET (warning) : toute cible d'alternate hreflang qu'aucun lien hypertexte ordinaire du crawl ne pointe est signalée. La ligne « Unlinked Hreflang URLs » de Screaming Frog est donc désormais couverte. Le contrôle lit l'export All Hreflang et la colonne Internal:All Inlinks, comme le fait UNLINKED_CANONICAL ; une auto-référence n'est pas comptée, et un crawl partiel retient le constat. Le registre passe de 182 à 183 contrôles.

    #1050 (ticket sur GitHub)
  • ModifiéFonctionneDimensionnement des images sur les routes rendues : render-check enregistre désormais la#1049

    taille…

    Dimensionnement des images sur les routes rendues : render-check enregistre désormais, pour chaque image, sa taille intrinsèque en pixels par rapport à sa boîte rendue et au device pixel ratio (image_sizing : preuves de surdimensionnement et d'agrandissement). Il ne s'agit que de preuves ; aucun identifiant de contrôle SF-analyzer n'existe encore, donc « Incorrectly Sized Images » passe de gap à partial (#1049).

    #1049 (ticket sur GitHub)
  • ModifiéFonctionneSemantically Similar : le statut reste gap, et la note indique désormais le blocage.#1041

    La commande et l'outil MCP de similarité sémantique existent, mais aucun adaptateur d'embeddings n'est livré et l'exécution SF n'appelle pas encore le module (#1041).

    #1041 (ticket sur GitHub)
  • AjoutéFonctionneAjout du contrôle INTERNAL_LINK_SPONSORED_UGC (notice) : un lien du même site portant#1040

    rel="sponsored" ou rel="ugc" est signalé avec l'ensemble complet de ses jetons rel. Il nécessite link_attributes.capture, comme les autres contrôles fondés sur rel, et est signalé comme non mesuré dans le cas contraire.

    #1040 (ticket sur GitHub)
  • AjoutéFonctionneAjout du cœur de génération de sitemap XML à partir d'un scan conservé :#1039

    select_indexable ne garde…

    Ajout du cœur de génération de sitemap XML à partir d'un scan conservé. select_indexable ne retient que les pages HTML en 200 qui sont auto-canoniques, non noindex et non bloquées par robots.txt, et indique la raison de chaque URL exclue. render_sitemaps écrit un <urlset>, ou des fichiers découpés plus un <sitemapindex> dès 50 000 URL ou 52 428 800 octets par fichier. L'exposition en CLI et en MCP suivra.

    #1039 (ticket sur GitHub)
  • AjoutéFonctionneAjout de cloudflare-traffic (CLI) et seo_cloudflare_traffic (MCP) : une source#1026

    Cloudflare GraphQL Analytics en lecture seule…

    Ajout de cloudflare-traffic (CLI) et seo_cloudflare_traffic (MCP) : une source GraphQL Analytics de Cloudflare en lecture seule, pour l'analyseur de logs lorsque les logs d'origine sont absents (#1026, #1009). Elle renvoie bots × URL × codes de statut × statut de cache par jour, au format de log-analyze, avec le libellé source: cloudflare-aggregated, car il s'agit de données de bord agrégées et non de logs bruts (pas d'IP client, donc pas de vérification par reverse DNS). Les jours qui atteignent le plafond de 10 000 lignes sont découpés en fenêtres horaires ; l'appel est compté dans le journal des dépenses comme fournisseur gratuit. Le jeton provient de CLOUDFLARE_API_TOKEN ou de SEOHEAD_CLOUDFLARE_TOKEN_FILE et n'est jamais affiché.

    #1026 (ticket sur GitHub)
  • ModifiéFonctionneÉvaluateur interne des constats Search Console, pas encore relié aux rapports :#1025

    seohead/checks/search_console_findings.py joint les pages du crawl à un document de preuves GSC normalisé et évalue GSC_ORPHAN, NO_SEARCH_DATA et NON_INDEXABLE_WITH_SEARCH_DATA. Un contrôle est ignoré, avec sa raison, lorsque le crawl est partiel, que la fenêtre est incomplète, que la collecte est échantillonnée ou tronquée, ou qu'aucune preuve n'est fournie ; un contrôle ignoré n'est jamais présenté comme propre.

    #1025 (ticket sur GitHub)
  • ModifiéFonctionnecrawl-enrich signale quatre constats d'analytics web à partir d'un CSV hors ligne#1024

    indexé par URL : URL orphelines selon les analytics, pages indexables sans donnée d'analytics, pages non indexables avec des visites, et taux de rebond supérieur à 70 %. Les options --visits-column et --bounce-column nomment les colonnes à lire ; une colonne absente est refusée par son nom, les valeurs illisibles sont comptées et jamais lues comme zéro, et les URL orphelines selon les analytics sont retenues sur un crawl partiel. La récupération en direct, URL par URL, depuis Metrika ou GA4 n'est pas encore incluse (#990, #984).

    #1024 (ticket sur GitHub)
  • ModifiéFonctionneLa carte de couverture des problèmes SF liste les quatre problèmes d'analytics web#1024

    (Orphan URLs, Bounce Rate…

    La carte de couverture des problèmes SF liste désormais les quatre problèmes d'analytics web (Orphan URLs, Bounce Rate Above 70%, No GA Data, Non-Indexable with GA Data) comme relevés par crawl-enrich à partir d'un CSV hors ligne, au lieu de les marquer hors périmètre. sf run ne les émet toujours pas.

    #1024 (ticket sur GitHub)
  • ModifiéFonctionneSocle de couverture lab pour le CSS et le JavaScript inutilisés (#1023, tranche 1) : un#1023

    analyseur pur prend…

    Socle de couverture lab pour le CSS et le JavaScript inutilisés (#1023, tranche 1) : un analyseur pur lit les charges page.coverage de Playwright et indique, pour chaque ressource, le nombre de caractères inutilisés, avec un constat lorsqu'une ressource est en grande partie inutilisée et volumineuse. La collecte de la couverture sur une page rendue fera l'objet de la tranche suivante.

    #1023 (ticket sur GitHub)
  • ModifiéFonctionneContrôles de paire AMP (#1020) : AMP_NON_200, AMP_MISSING_CANONICAL,#1020

    AMP_MISSING_RETURN_LINK, AMP_NON_INDEXABLE_CANONICAL et AMP_INDEXABLE lisent la cible AMP déclarée par une page desktop avec <link rel="amphtml">. Seules les pages AMP capturées par le crawl sont jugées ; une cible non capturée donne un contrôle ignoré, avec sa raison. Le crawl natif enregistre désormais la cible résolue dans la colonne AMP HTML. Les dix autres règles AMP de SF restent hors périmètre.

    #1020 (ticket sur GitHub)
  • AjoutéFonctionneAjout de HTML_OVER_2MB, un plafond absolu de 2 Mo sur un document HTML, distinct de#1019

    LARGE_HTML, qui est relatif à la médiane. La ligne « HTML Document Over 2MB » de Screaming Frog pointe désormais vers ce contrôle, et non plus vers la règle des 200 Ko.

    #1019 (ticket sur GitHub)
  • AjoutéFonctionneAjout de la notice URL_HAS_PARAMETERS à l'audit de crawl : une page HTML interne dont#1018

    l'URL porte des paramètres de requête est signalée, quel que soit son statut canonique. URL_HAS_PARAMS conserve son sens plus étroit, limité aux pages sans balise canonical (#1018).

    #1018 (ticket sur GitHub)
  • ModifiéFonctionneDirectives robots (#1017) : les anciennes noodp et noydir dans la meta robots ou#1017

    X-Robots-Tag…

    Directives robots (#1017) : les anciennes noodp et noydir, présentes dans la meta robots ou dans X-Robots-Tag, déclenchent désormais les notices NOODP et NOYDIR dans l'audit SF, alors qu'elles étaient listées hors périmètre. none (noindex + nofollow) est couvert par des tests de non-régression pour le chemin X-Robots-Tag comme pour le chemin meta.

    #1017 (ticket sur GitHub)
  • AjoutéFonctionneNouveau contrôle de crawl JS_CONSOLE_ERRORS (SF « Pages with JavaScript Errors ») : une#1015

    page dont la console du rendu conservé a enregistré des erreurs. Il est lu hors ligne, à partir des sidecars de console sauvegardés d'un scan natif, sans nouveau rendu ; un enregistrement illisible donne un contrôle ignoré et motivé, jamais une page déclarée propre. Nécessite rendering.artifacts.console_errors.

    #1015 (ticket sur GitHub)
  • ModifiéFonctionneLes crawls signalent désormais quatre en-têtes de sécurité manquants par page HTML,#1013

    d'après la réponse finale conservée : MISSING_CSP, MISSING_X_CONTENT_TYPE_OPTIONS, MISSING_X_FRAME_OPTIONS (satisfait par une directive CSP frame-ancestors) et MISSING_REFERRER_POLICY. Les pages dont les en-têtes conservés ne peuvent pas être analysés sont comptées comme non mesurées, et non comme propres ; un crawl sans scan conservé ignore ces pages en indiquant la raison.

    #1013 (ticket sur GitHub)
  • AjoutéFonctionneAjout d'un validateur des specs d'actions de page à liste fermée (click, scroll,#1011

    wait_for_selector, wait_ms), avec un budget de temps statique pour les crawls rendus. Il n'est pas encore branché au rendu : le comportement des crawls est donc inchangé (#1011).

    #1011 (ticket sur GitHub)
  • ModifiéFonctionnelog-analyze lit les journaux d'accès compressés en gzip (fichiers access.log.N.gz#1009

    pivotés et archives renommées)…

    log-analyze lit directement les journaux d'accès compressés en gzip (fichiers access.log.N.gz pivotés et archives renommées), en détectant le format d'après le contenu et non d'après l'extension. Une archive tronquée ou corrompue est signalée comme erreur, sans comptages partiels.

    #1009 (ticket sur GitHub)
  • ModifiéFonctionnescan-url-query ajoute des préréglages de vue prêts à l'emploi (--preset, par exemple#1007

    status_4xx, title_missing, title_over_60, h1_missing, noindex_meta), combinés par un ET logique avec vos filtres. --export PATH avec --export-format csv|xlsx écrit chaque ligne correspondante dans un nouveau fichier. L'export est refusé au-delà de --export-max-rows (100 000 par défaut) et n'écrase jamais un fichier existant.

    #1007 (ticket sur GitHub)
  • ModifiéFonctionneLes règles d'éligibilité aux résultats enrichis quittent le code Python pour#1001

    seohead/data/rich_results_rules.json, un fichier de données versionné, livré avec le paquet. Sa valeur version est reprise comme rules_version sur chaque verdict de résultat enrichi : modifier une règle revient donc à modifier des données, et non du code.

    #1001 (ticket sur GitHub)
  • ModifiéFonctionneLes verdicts résultats enrichis (check_schema et les contrôles de preuves structurées#1001

    stockées) portent désormais rules_version, afin que chaque résultat indique l'ensemble de règles hors ligne qui l'a produit.

    #1001 (ticket sur GitHub)
  • ModifiéFonctionneDocumentation de six scripts de maintenance et de génération absents de la documentation…#997

    Documentation des six scripts de maintenance et de génération qui n'étaient cités nulle part dans la documentation (scripts/generate_project_catalogue.py, generate_registry_inventory.py, render_readme_visuals.py, linux_lifecycle_smoke.py, capacity_watchdog.py, profile_million_audit.py) dans docs/README.md, avec ce que chacun écrit et ceux qui tournent en CI (#997).

    #997 (ticket sur GitHub)
  • AjoutéFonctionneAjout du pipeline semantic core sous seohead/semantics, avec sa base SQLite propre à#995

    chaque projet…

    Ajout du pipeline semantic core sous seohead/semantics, avec sa propre base SQLite par projet : seohead semantics <stage> --project DIR (init, import, collect, clean, graph, exact, cluster, competitors, synonyms, report, excel, mine, sitematch, relevance, status, export), les outils MCP seo_semantics_status, seo_semantics_run, seo_semantics_mine et seo_semantics_paid (les étapes payantes exigent confirm_paid=true), le clustering Louvain derrière le nouvel extra semantics, le skill semantic-core livré avec le paquet et un projet d'exemple synthétique. Les frais fournisseurs d'une étape sémantique sont marqués dans le journal de dépenses partagé (#995).

    #995 (ticket sur GitHub)
  • ModifiéFonctionneSuppression de l'adaptateur bot Telegram guidé seohead/integrations/bot ; les accusés#995

    de livraison du monitoring vivent désormais dans seohead/projects/service_delivery.py (#995).

    #995 (ticket sur GitHub)
  • ModifiéFonctionnescan-url-query renvoie click_depth, le plus court chemin de liens internes depuis la#992

    page de départ du scan, sous forme de colonne, de filtre et de clé de tri. Les pages qu'aucun lien stocké n'atteint valent NULL (orphelines). crawl_depth ne change pas et reste la profondeur de la frontière de crawl, qui vaut 0 pour toute URL issue du sitemap. Un scan qui n'a pas conservé ses liens échoue avec reason_code: click_depth_unavailable au lieu d'afficher un faux NULL. La valeur est recalculée à chaque requête à partir de la table links ; la stocker en colonne indexée à la fin du scan reste à traiter, car cela suppose une décision sur la version du schéma (#992).

    #992 (ticket sur GitHub)
  • ModifiéFonctionnescan-url-query et son outil MCP acceptent un argument facets facultatif (une liste#991

    d'identifiants de groupes, ou all)…

    scan-url-query et son outil MCP acceptent un argument facultatif facets (une liste d'identifiants de groupes, ou all) qui renvoie, en une seule passe et sur les mêmes filtres, le nombre de résultats par groupe (status_2xx–5xx, title_missing, canonical_missing, directives_noindex/nofollow, with_outlinks). Les groupes qui exigent une projection (internes ou externes, sitemap, doublon et longueur de title, canonical pointant sur soi ou ailleurs) ne sont pas encore inclus.

    #991 (ticket sur GitHub)
  • ModifiéFonctionneLiaisons de sources de projet, première tranche (#990) : project-sources-link,#990

    project-sources-unlink et project-sources-list (CLI, ainsi que seo_project_sources_link|unlink|list via MCP) enregistrent les identifiants de ressources fournisseur qu'un projet local utilise, dans sources.json à côté de project.json. Hors ligne seulement : ni découverte, ni appel fournisseur, ni identifiants ; project.json n'est jamais réécrit.

    #990 (ticket sur GitHub)
  • ModifiéFonctionneCrawl natif : nouveau contrôle IMG_BROKEN (#989, tranche 1) signale les cibles de <img>#989

    ayant répondu 4xx/5xx, avec la page source comme preuve. Il lit le graphe de ressources stocké et s'ignore honnêtement lorsqu'aucune image n'a été mesurée.

    #989 (ticket sur GitHub)
  • AjoutéFonctionneAjout d'un classifieur pur de soft 404 sur le corps de page stocké#988

    (classify_stored_soft404) : texte vide, phrase d'erreur sur une page légère, et correspondance simhash avec un gabarit 404. Il n'est pas encore branché au crawl et n'émet aucun constat ; c'est la première tranche de l'issue #988.

    #988 (ticket sur GitHub)
  • ModifiéFonctionneLes crawls natifs sondent les cibles canonical et hreflang qu'aucun lien n'a atteintes,#987

    une fois par cible…

    Les crawls natifs sondent, une fois par cible après le crawl (5 000 au maximum), les cibles canonical et hreflang qu'aucun lien n'a atteintes. Une cible en 4xx/5xx ou en redirection donne alors CANONICAL_TARGET_ERROR, CANONICAL_TO_REDIRECT ou HREFLANG_BROKEN_TARGET, comme cela se faisait déjà pour les cibles crawlées (#987).

    #987 (ticket sur GitHub)
  • ModifiéFonctionneLes constats de chaîne et de boucle de redirections issus d'un crawl natif portent#985

    désormais le chemin complet des sauts (details.path), pour qu'une correction puisse nommer chaque saut à remplacer. Réf. #985.

    #985 (ticket sur GitHub)
  • ModifiéFonctionneLes constats de chaîne et de boucle de redirections issus d'un crawl natif portent#985

    désormais aussi…

    Les constats de chaîne et de boucle de redirections issus d'un crawl natif portent aussi details.inbound_links (liens internes pointant encore vers la première URL de la chaîne, avec leurs ancres, plafonnés à 20) et inbound_links_count. Sans inventaire all_inlinks, le champ vaut null avec une raison. Réf. #985.

    #985 (ticket sur GitHub)
  • ModifiéFonctionneLes projets peuvent enregistrer un lien vers leur semantic core sous forme de faits#984

    saisis par l'opérateur (semcore_project, semcore_cluster_count, semcore_landing_mapping). Le semantic core reste dans sa propre base et n'est pas fusionné dans la base du projet ; la détection n'écrit jamais ces faits, et un fait fourni ne peut pas revendiquer une provenance de détection. Documenté dans docs/PROJECTS.md, section « Linking a semantic core » (partiel, #984).

    #984 (ticket sur GitHub)
  • ModifiéFonctionneApplication de bureau : l'écran Link graph suit la maquette GraphFilters (canevas et#975

    panneau de filtres).

    Le core ne renvoie pas encore tout le graphe de liens : le canevas affiche donc un état d'attente honnête, et les filtres restent inactifs tant que ce n'est pas le cas (#975).

    #975 (ticket sur GitHub)
  • ModifiéFonctionneOAuth GSC : provider-auth --action cancel (CLI) et seo_provider_auth action=cancel#964

    (MCP) annulent un enregistrement de flux de consentement navigateur en attente ; status signale le flux en attente lorsqu'il existe. L'enregistrement du flux ne stocke aucun élément d'autorisation et expire au bout de dix minutes. C'est la première tranche de #964 : pas encore de démarrage ni de callback navigateur, donc aucun flux n'est créé par l'interface publique, et un accès connecté n'est toujours jamais revendiqué.

    #964 (ticket sur GitHub)
  • ModifiéFonctionnecrawl-site --urls/--urls-file --project enregistre désormais le crawl par liste d'URL#962

    comme exécution observée (mode=list) : il apparaît dans project-observe et project-scans, avec son artefact dans le dossier scans/ du projet. Un collecteur en échec est noté failed ; la progression et la reprise des exécutions par liste ne sont pas encore couvertes (#962).

    #962 (ticket sur GitHub)
  • AjoutéFonctionneAjout d'un plan structuré des playbooks : skill-list et scenario-list renvoient les#955

    étapes ordonnées de chaque playbook, et skill-show / scenario-show ajoutent ses titres et ses étapes, afin qu'un agent lise la forme de la méthode sans analyser le markdown (#955). Nouvelle commande CLI scenario-list et nouvel outil MCP seo_scenario_list.

    #955 (ticket sur GitHub)
  • ModifiéFonctionnescan-content-search accepte --kind regex (MCP kind="regex") pour chercher dans les#954

    documents conservés à l'aide d'une expression régulière Python. Les expressions invalides sont refusées avant le scan ; un document qui dépasse le budget de temps de la regex est signalé comme indisponible, jamais comme absent.

    #954 (ticket sur GitHub)
  • ModifiéFonctionneLes appels DataForSEO dont la réponse est perdue (erreur réseau après l'envoi de la#949

    requête) sont journalisés avec cost_unknown…

    Les appels DataForSEO dont la réponse est perdue (erreur réseau après l'envoi de la requête) sont journalisés avec cost_unknown et charge_status: unknown, afin que spend-report les liste comme incertains au lieu de les compter comme un appel mesuré à coût nul (#949).

    #949 (ticket sur GitHub)
  • AjoutéFonctionneNouvelle commande scan-structured-blocks (CLI) et outil MCP#948

    seo_scan_structured_blocks…

    Nouvelle commande scan-structured-blocks (CLI) et nouvel outil MCP seo_scan_structured_blocks : pour une URL conservée, décrit chaque bloc JSON-LD (sa ligne source, son statut valid / errors / warnings / parse_error, ses types, une liste à plat de ses propriétés, le JSON source borné et les erreurs du graphe Schema.org). Fonctionne hors ligne, sur le corps de page complet conservé uniquement ; aucune requête réseau et aucune modification des artefacts.

    #948 (ticket sur GitHub)
  • ModifiéFonctionnecrawl-site sans projet, qui écrit un artefact de scan SQLite, partage désormais son#942

    plafond de requêtes par hôte…

    crawl-site sans projet qui écrit un artefact de scan SQLite partage désormais son plafond de requêtes par hôte avec les autres crawls simultanés du même hôte, grâce à un planning privé stocké dans le répertoire d'état utilisateur (~/.config/seohead/.origin-pacing.sqlite). Auparavant, les crawls sans projet tournaient sans cadence entre processus.

    #942 (ticket sur GitHub)
  • ModifiéFonctionneProfils crawl-site (#941) : crawl-profile list affiche les noms des profils enregistrés#941

    et…

    Profils crawl-site (#941) : crawl-profile list affiche les noms des profils enregistrés, et crawl-profile delete NAME supprime l'un d'eux. Les deux sorties sont en JSON, et les noms inconnus sont refusés avec la liste des profils enregistrés.

    #941 (ticket sur GitHub)
  • ModifiéFonctionneProfils crawl-site (#941) : --save-profile NAME --config FILE enregistre une config#941

    validée…

    Profils crawl-site (#941) : --save-profile NAME --config FILE enregistre une config de crawl validée comme profil nommé (refusée si elle contient des en-têtes d'identifiants) ; --profile NAME lance le crawl avec ce profil, et --set s'applique toujours par-dessus. Les profils sont stockés dans ~/.config/seohead/crawl-profiles ou dans le répertoire indiqué par SEOHEAD_CRAWL_PROFILES. La liste et la suppression des profils ne font pas partie de cette tranche.

    #941 (ticket sur GitHub)
  • ModifiéFonctionnecompare.v1 liste désormais les pages crawlées d'un seul côté (url_sets :#938

    only_in_before, only_in_after, avec compteurs). Lorsque l'un des deux crawls est partiel, url_sets.unproven vaut true, afin que l'absence ne soit pas présentée comme une preuve.

    #938 (ticket sur GitHub)
  • ModifiéFonctionneChaque saut des chaînes de redirections et de canonicals enregistre son statut, la#930

    Location suivante et son temps de réponse…

    Chaque saut des chaînes de redirections et de canonicals enregistre son statut, la Location suivante (redirections) et son temps de réponse, afin que la chaîne d'une URL se lise à partir des preuves stockées, sans nouvelle requête (#930).

    #930 (ticket sur GitHub)
  • ModifiéFonctionneLes boucles de redirection des chaînes par URL se terminent par une étape marqueur#930

    ({"url": ..., "loop": true}) qui n'est plus récupérée ; l'URL répétée reste ainsi visible dans les preuves stockées. final_url pointe toujours sur le dernier saut réellement récupéré (#930).

    #930 (ticket sur GitHub)
  • AjoutéFonctionneExposition des étapes de création et d'ingestion de scan du registre de remédiation via#926

    la CLI et MCP : remediation-create / seo_remediation_create crée un registre vide, lié à un projet (producer_build doit être un SHA Git complet de 40 caractères ; les chemins existants sont refusés), et remediation-ingest / seo_remediation_ingest ingère un audit enregistré comme référence (baseline) et historique, sans relancer de crawl (une nouvelle ingestion de la même révision est idempotente). La logique de stockage ne change pas ; c'est la première tranche de #926.

    #926 (ticket sur GitHub)
  • ModifiéFonctionnecrawl_site et les exécutions de scan indiquent effective_max_requests_per_second et#925

    warnings : un avertissement apparaît lorsque la cadence effective dépasse 2 req/s (le seuil est strictement supérieur à 2). La CLI affiche le même avertissement sur stderr ; le JSON sur stdout et les valeurs par défaut ne changent pas. Le pacer n'a pas été modifié.

    #925 (ticket sur GitHub)
  • ModifiéFonctionneJournal d'événements structuré du projet (events.jsonl) : événements en ajout seul,#923

    avec source, acteur et texte borné, lus du plus récent au plus ancien par pages, avec filtres de source et de texte. Exposé sous project-event-append / project-event-page dans la CLI et sous seo_project_event_append / seo_project_event_page via MCP (issue #923).

    #923 (ticket sur GitHub)
  • AjoutéFonctionneAjout de la commande ai-column et de l'outil MCP seo_ai_column, première tranche de

    la colonne personnalisée IA (réf. #1012). Sur des pages de scan conservées et sélectionnées, ou sur des éléments normalisés fournis, elle prépare un plan borné à partir du title, des titres et d'un extrait de texte, avec une estimation de taille en caractères (sans prix appliqué) et le périmètre de consentement que l'agent appelant doit respecter avant tout transfert. Les valeurs par URL fournies sont validées par rapport au hash source de chaque page ; les valeurs manquantes, périmées, vides ou trop grandes sont signalées comme telles et jamais remplies. Un CSV facultatif, protégé contre l'injection de formules, exporte la colonne. SEOHEAD ne détient aucune clé fournisseur et n'effectue aucun appel à un modèle.

  • ModifiéFonctionneMutualisation des ouvreurs SQLite en lecture seule et en écriture dans

    seohead.core.sqlite.

    Les lecteurs de stockage, l'importeur de scans, l'archive GSC, le stockage des sources, le stockage de jointure de preuves et les deux classes de contrôles ouvrent désormais leurs bases via un seul helper pour la connexion, la row factory et les PRAGMA. Les deux classes de contrôles ferment explicitement leurs connexions. Le comportement ne change pas ; la normalisation des chemins et l'ordre des PRAGMA restent à chaque point d'appel.

  • ModifiéFonctionneCorrections de fond issues d'une relecture des contrôles, des sources de données et de

    l'import de preuves.

    Changements de comportement voulus sur ces chemins : - Les chaînes de redirections d'exactement la limite de sauts (20 par défaut) sont désormais résolues au lieu d'être signalées comme non résolues. Le contrôle de boucle s'exécute avant le contrôle de limite, dans la résolution de chaîne comme dans le parcours des chemins de sauts. - Les contrôles de confiance et de citation EEAT comparent les hôtes de destination avec leur port (netloc), comme la logique d'hôte des liens internes. Les sites avec ports explicites peuvent voir leurs résultats changer. - Les contrôles de mots-clés llms.txt font correspondre les termes ASCII comme des mots entiers, avec un pluriel facultatif : rapid, Showcase et Toolbar ne passent plus. Les radicaux en cyrillique continuent de correspondre comme sous-chaînes. - La capture de navigation fait correspondre le motif reload à refresh_navigation. Les motifs demandés non reliés, comme pageBlockInterstitial, sont enregistrés comme observations de cadre que le validateur accepte. - La détection de technologies traite une implication niée (["not", X]) comme n'impliquant rien. - L'import de preuves rejette les noms de métriques déclarés en double, et la découverte Search Console utilise les lignes qu'elle reçoit. - Les nouvelles tentatives Yandex Cloud ne marquent une pause qu'entre deux tentatives. Les nouvelles tentatives de l'analyse des requêtes Yandex Webmaster attendent avant la tentative suivante. - La construction du schéma transmet son timeout au client HTTP (valeur par défaut inchangée). - Le stockage des reçus de livraison est créé en mode 0600 avant que SQLite ne l'ouvre. - Les exécutions du graphe sémantique sont sérialisées, car l'ensemble des mots vides est un état de module. Le runner sémantique signale les erreurs SQLite par ok: false au lieu de les lever. - Le parseur d'erreurs CrUX tolère les corps de réponse qui ne sont pas des objets. - Suppression d'une garde sqlite3 is None inatteignable dans le registre.

  • ModifiéFonctionneApplication de bureau : un écran Backlinks dans la mise en page design-v2.

    Il affiche l'état d'attente honnête tant que le core ne stocke pas de profil de liens du projet (#999) ; pas de lignes d'exemple, et les filtres de groupe sont désactivés pour la même raison.

  • ModifiéFonctionneApplication de bureau, écran Crawler : bannière des résultats temporaires avec l'adresse

    sélectionnée et son statut…

    Application de bureau, écran Crawler : ajout de la bannière des résultats temporaires avec l'adresse sélectionnée et le texte de statut (affichée seulement quand un crawl sans projet renvoie des résultats) ; déplacement des actions d'effacement et d'enregistrement comme projet dans un menu de débordement sous 1 000 px ; champ d'adresse et bande d'onglets de contrôle utilisables sur les largeurs étroites ; défilement de l'en-tête des résultats au lieu de compresser ses colonnes ; même marge droite de 8 px sur la barre de statut de l'interface, en thème sombre comme en thème clair.

  • ModifiéFonctionneApplication de bureau : écran des états bloquants, un par canevas (ErrorsCore).

    Le core manquant, l'espace disque faible et l'absence d'accès en écriture sont affichés à partir de faits réels ; la version du core et l'intégrité des scans affichent la pastille neutre « unavailable in this core version » tant que le core ne les fournit pas.

  • ModifiéFonctionneApplication de bureau : le menu de ligne d'URL et le menu d'en-tête de colonne, les

    groupes de la barre de menus Edit, Scan et Window, ainsi que les menus contextuels des constats et des tâches suivent le tableau Menus du canevas. Les entrées que le core ne fournit pas encore restent visibles mais désactivées, avec la raison dans l'infobulle.

  • ModifiéFonctionneApplication de bureau : l'écran « Export et rapports » suit le canevas ProjExport (jeu de

    données, format…

    Application de bureau : l'écran « Export et rapports » suit le canevas de conception ProjExport (choix du jeu de données et du format, carte de dossier, exports récents). Les jeux de données et formats que le core ne sait pas encore exporter (comparaison, tâches, PDF) sont affichés comme indisponibles ; le bouton d'exécution reste désactivé tant que l'export n'est pas branché (#1191).

  • ModifiéFonctionneNeutraliser les TAB et CR en tête dans les identifiants d'inventaire marketing et les CSV

    de relecture…

    Neutralisation des TAB et CR en tête dans les identifiants d'inventaire marketing et dans les CSV de relecture des brouillons de meta description, avec le même préfixe apostrophe que celui déjà appliqué à =, +, - et @. Les deux protections utilisent désormais seohead.core.tabular.neutralize_formula.

  • ModifiéFonctionneRequêtes fournisseur avec identifiants (Arsenkin, Metrika, Yandex Cloud, IndexNow…

    Les requêtes fournisseur qui transportent des identifiants (Arsenkin, Metrika, Yandex Cloud, IndexNow, Topvisor, destinations BI) ne suivent plus les redirections HTTP : un en-tête Authorization n'est donc jamais renvoyé à un autre hôte. Une redirection remonte désormais comme une erreur HTTP du fournisseur.

  • AjoutéFonctionneAjout d'un format de redirection csv (lignes source,target,301, entre guillemets si

    nécessaire) dans…

    Ajout du format de redirection csv (lignes source,target,301, entre guillemets si nécessaire) à generate_rule et à l'aide de la CLI redirects-generate. Le format wordpress-redirection n'est pas inclus, car sa syntaxe d'import n'a pas été vérifiée (#998).

  • ModifiéFonctionneLe journal d'exécution (runs.jsonl) fait désormais une rotation au-delà d'une taille

    limite (5 Mo…

    Le journal d'exécution (runs.jsonl) fait désormais une rotation dès qu'il dépasse une taille limite (5 Mo par défaut ; SEOHEAD_RUN_LOG_MAX_BYTES permet de la modifier). La génération précédente est conservée sous le nom runs.jsonl.1, et les lectures portent sur les deux fichiers, si bien que les recherches de réutilisation voient toujours les appels récents.

  • ModifiéFonctionneMise en page de l'onglet Schema de la carte d'URL desktop selon la structure canvas

    design-v2 (liste de blocs, arbre de blocs, contrôles). Le cœur ne renvoie que le nombre de blocs JSON-LD par URL : les colonnes affichent donc des états d'attente honnêtes, liés à l'issue 948 du cœur, et les comptes connus restent réels. Aucun bloc d'exemple n'est affiché.

9 octobre 2026

4 ajouté4 modifié
  • AjoutéFonctionneLibellés de terminal RU/EN selon la langue, bloc de progression du scan en cours,#951

    sélection explicite…

    Ajout de libellés de terminal RU/EN selon la langue choisie, d'un bloc de progression du scan en cours, d'une sélection explicite de scan et d'une sortie compacte de l'observateur.

    #951 (ticket sur GitHub)
  • ModifiéFonctionneLes scans sauvegardés s'ouvrent en lecture légère (#931).#931

    scan-status, scan-url-detail, scan-link-inspect et l'observateur de projet (project-scans, project-observe) ne valident plus l'intégralité de l'artefact à chaque ouverture : ils vérifient l'identité, le schéma, la version et la ligne d'en-tête, prennent les compteurs en SQL (GROUP BY sur pages_status) et l'indiquent dans un champ validation ajouté ("light" ou "full"). La validation complète est lancée sur demande (full_validation: true sur scan-status, ou --input '{"input_path": "...", "full_validation": true}' en CLI), ou lorsque les mêmes octets (chemin, taille, date de modification, état WAL, hachage d'en-tête) ont déjà été entièrement validés dans le processus. Un scan qui échoue aux contrôles légers est refusé avec la même erreur qu'auparavant, et chaque chemin d'écriture ou d'enregistrement de preuves continue de valider intégralement. scan-url-detail exécute la recherche de la cible de redirection (sans index sur responses.effective_url_id) dans un budget de 0,5 s, et renvoie responses.redirect_target_lookup avec la valeur skipped au lieu de parcourir une table volumineuse.

    #931 (ticket sur GitHub)
  • AjoutéFonctionneÉtat MCP partagé et audité, avec révocation au démarrage et en direct des appels d'outils#929

    ; présence…

    Ajout d'un état MCP partagé et audité, avec révocation au démarrage et en cours d'exécution des appels d'outils ; la présence sécurisée des clients est exposée via la CLI.

    #929 (ticket sur GitHub)
  • AjoutéFonctionneEnregistrement de clients avec autorisation explicite : aperçus, écritures atomiques,#929

    sauvegardes…

    Ajout de l'enregistrement de clients avec autorisation explicite : aperçus, écritures atomiques, sauvegardes vérifiées et restauration sans conflit.

    #929 (ticket sur GitHub)
  • AjoutéFonctionneAjout de scan-url-query (MCP seo_scan_url_query) : lecture seule, filtrée, triée et#927

    paginée côté serveur, de l'ensemble de la table des pages d'un scan enregistré. Elle renvoie total, filtered_total (null avec filtered_total_state: capped lorsque le décompte dépasse son budget de temps), une projection de colonnes, les libellés de couverture du scan, le format seohead.scan-url-query.v1 et un reason_code lisible par machine pour chaque échec. Au maximum 200 lignes par appel. Le tri par url, status_code, page_ordinal ou url_id utilise les index ; toute autre colonne exige un filtre qui laisse au plus 100 000 lignes (sinon sort_not_indexed). Le scan est ouvert avec une vérification légère de l'identité et de la génération du schéma, et non avec une validation complète, et il n'est jamais modifié.

    #927 (ticket sur GitHub)
  • ModifiéFonctionnescan-link-inspect --view links (MCP seo_scan_link_inspect) pagine les liens sortants#924

    ou…

    scan-link-inspect --view links (MCP seo_scan_link_inspect) pagine les liens hypertextes sortants ou entrants d'une URL, recherchée par adresse et non par identifiant de document : ancre, rel avec les indicateurs nofollow/sponsored/ugc, lien interne ou externe, position enregistrée, attribut target et code HTTP de l'autre extrémité (null si cette page n'a pas été scannée). Filtres par type de lien, suivi, classe de statut et sous-chaîne ; offset/limit jusqu'à 200 ; total/filtered_total sont exacts ou signalés comme plafonnés. Le scan est ouvert en lecture seule sans validation complète, et les échecs portent un reason_code lisible par machine (url_not_found, scan_not_available, url_not_scanned, links_not_retained). Les vues et champs existants restent inchangés.

    #924 (ticket sur GitHub)
  • ModifiéFonctionneRéorganisation du paquet sans couche de compatibilité : seohead.servers devient

    seohead.mcp…

    Réorganisation de l'arborescence du paquet, sans couche de compatibilité : seohead.servers devient seohead.mcp, seohead.tools devient seohead.checks, seohead.bot et seohead.remote_api passent sous seohead.integrations, la CLI vit dans le paquet seohead.cli (avec seohead.cli.terminal_progress), les modules racine partagés (models, graph, filesystem, runlog, verification, canonical_policy, input_contracts, job_contracts, provider_matrix) passent dans seohead.core, et la provenance de build passe dans seohead._build.provenance. examples/ et config.example.json sont déplacés vers docs/examples/ ; PROVENANCE.md et TRADEMARKS.md vers docs/legal/. Les commandes seohead et sf-analyzer ne changent pas, mais les imports Python qui utilisent les anciens chemins de modules doivent être mis à jour.

  • ModifiéFonctionneRéécriture du README : installation, trois parcours de démarrage rapide (du crawl natif

    au rapport…

    Réécriture du README autour de l'installation, de trois parcours de démarrage rapide (du crawl natif au rapport, exports Screaming Frog hors ligne, projet et agent), d'une carte des fonctionnalités par domaine, d'un aperçu de la CLI, de la configuration MCP pour Claude Code et Claude Desktop, de l'application de bureau compagnon et de la frontière entre mesuré et non mesuré, avec de vraies captures du terminal sous docs/assets/, réalisées à partir d'une fixture QA locale et de la fixture d'export synthétique. Ajout de docs/CLI.md, qui regroupe chaque commande enregistrée par tâche avec ses annotations réseau, écriture et payante (un test de dérive échoue désormais si une commande manque), et de docs/WORKFLOWS.md, qui documente les commandes workflow-run, inbox et monitor-record, jusque-là seulement référencées.

8 octobre 2026

1 ajouté10 modifié1 corrigé
  • CorrigéFonctionneComptage des octets HTML/DOM conservés local à la transaction et incrémental, au lieu de…#914

    Le comptage des octets HTML/DOM conservés reste local à la transaction et incrémental, au lieu de reparcourir tous les corps stockés pour chaque réponse unique. Les instances d'écriture rouvertes reconstruisent le compteur une seule fois ; la déduplication, le rollback, les savepoints et les limites de conservation des corps restent intacts.

    #914 (ticket sur GitHub)
  • ModifiéFonctionneLe reporting BI garde à l'état inconnu les états de collecte fournisseur non vérifiés et#833

    les indicateurs…

    Le reporting BI maintient à l'état inconnu les états de collecte fournisseur non vérifiés et les indicateurs de qualité dans les métriques, la couverture et les manifestes ; un échantillonnage, un seuillage ou une troncature confirmé est considéré comme partiel. Les cohortes recherche contre sessions exigent une qualité de collecte explicite, des mesures de comptage non négatives et des périmètres de source qualifiés, et conservent pour chaque axe l'identité de la source, l'attribution, le périmètre de recherche et la politique calendaire. Le paquet de reporting synthétique reste hors ligne ; l'acceptation native dans Sheets et Looker reste distincte.

    #833 (ticket sur GitHub)
  • ModifiéFonctionneLes scans natifs SQLite acceptent max_urls=0 pour collecter jusqu'à épuisement de la#818

    file…

    Les scans de site natifs SQLite acceptent max_urls=0 pour collecter jusqu'à épuisement de la file, et max_depth=-1 pour désactiver la limite de profondeur. Les budgets de temps et HTTP restent configurables séparément, les garde-fous de stockage ainsi que l'interruption et la reprise restent actifs, et les routes matérialisées héritées refusent une population d'URL illimitée.

    #818 (ticket sur GitHub)
  • ModifiéFonctionneLes scans limités aux sitemaps conservent aussi la limite d'URL désactivée, au lieu de#818

    refuser…

    Les scans limités aux sitemaps conservent eux aussi la limite d'URL désactivée, au lieu de refuser leur premier membre déclaré lorsque la limite configurée vaut zéro.

    #818 (ticket sur GitHub)
  • ModifiéFonctionneLes débits explicites finis au-dessus de 2 requêtes/s atteignent désormais la voie de#818

    cadencement partagée…

    Les débits de requêtes explicites, finis et supérieurs à la valeur par défaut de 2 requêtes/s atteignent désormais la voie de cadencement partagée par origine de projet, en plus du limiteur par scan. Les scans parallèles réservent un seul calendrier commun par hôte au lieu de multiplier son débit.

    #818 (ticket sur GitHub)
  • ModifiéFonctionneL'interruption de l'analyse native renvoie un résultat explicite, reprenable, et conserve#754

    les pages…

    L'interruption de l'analyse native renvoie désormais un résultat explicite « interrompu et reprenable » et conserve les pages capturées, au lieu d'afficher une trace KeyboardInterrupt.

    #754 (ticket sur GitHub)
  • ModifiéFonctionneRégénération du catalogue de projets packagé après la mise à jour du scénario du provider#754

    Bing.

    #754 (ticket sur GitHub)
  • ModifiéFonctionneRejet des lignes de réponse Bing Webmaster mal formées, au lieu de signaler un résultat#753

    vide complet…

    Rejeter les lignes de réponse Bing Webmaster mal formées au lieu de signaler un résultat vide complet. Conserver les données brutes de réponse, les lignes sources et les comptes exacts renvoyés dans les preuves fournisseur enregistrées. Les réponses de comptage de liens conservent leur enveloppe de pagination documentée et signalent comme partielles les populations sur plusieurs pages lorsque seule une page demandée a été collectée.

    #753 (ticket sur GitHub)
  • ModifiéFonctionneReconnaissance du fallback de compte de service Google partagé dans la disponibilité GA4…#753

    Reconnaître le fallback existant de compte de service Google partagé dans la vérification de disponibilité et la découverte des identifiants du provider GA4. Les permissions du compte et l'accès aux cibles restent non vérifiés, les identifiants mal formés sont signalés explicitement, et la prise en charge du bearer OAuth est conservée sans exiger les deux sources.

    #753 (ticket sur GitHub)
  • ModifiéFonctionneLier les références de capacités headless à l'isolation des exécutions natives et à la#743

    frontière publique de routage des crawls externes, en distinguant l'implémentation interne de la disponibilité CLI/MCP, sans modifier le comportement de crawl ni les revendications de capacité.

    #743 (ticket sur GitHub)
  • AjoutéFonctionnePagination bornée des exécutions terminées dans project-observe (CLI et MCP), en

    gardant…

    Ajout d'une pagination bornée des exécutions terminées à project-observe, en CLI et en MCP, tout en gardant visible chaque enregistrement d'exécution en cours stocké. Les pages conservent les identifiants d'exécution exacts et l'ordre d'admission inverse ; les compteurs et les métadonnées de rétention décrivent le magasin actuel de 100 enregistrements, et non l'historique complet. La lecture ne modifie jamais les états d'exécution stockés. Les entrées JSON de la CLI conservent leur pagination et leur périmètre de projet, sauf si un drapeau nommé explicite les remplace.

  • ModifiéFonctionneGestion de Ctrl+C sur toute la transmission native après collecte, y compris l'ouverture

    du scan…

    Gérer Ctrl+C sur toute la transmission native après collecte : ouverture du scan sauvegardé, phases de suivi facultatives, analyse et finalisation. Les captures inachevées conservent leurs données ainsi que leur point de contrôle reprenable, et renvoient un résultat JSON interrompu explicite. Une interruption après le commit final préserve l'artefact terminé et indique sa disponibilité d'audit réelle. La reprise explicite termine le travail post-collecte inachevé, même avec une frontière de crawl vidée, en préservant les drapeaux d'omission de preuves existants et les entrées sitemap conservées.

7 octobre 2026

4 ajouté4 modifié1 corrigé
  • AjoutéFonctionneFixture Linux jetable pour l'exécution réelle de workers SSH par clé, les téléchargements#754

    API/TLS…

    Ajouter une fixture Linux jetable pour l'exécution réelle de workers SSH par clé, les téléchargements API/TLS authentifiés et l'erreur ENOSPC du worker natif sur un tmpfs réservé aux jobs. Préserver la file et les preuves, et exiger un résultat explicite de non-réussite, sans rejeu, avant un nouveau job de récupération JS. Préciser les mesures locales du cycle de vie, par opposition aux preuves SSH et de confinement OS.

    #754 (ticket sur GitHub)
  • ModifiéFonctionneConservation des preuves JavaScript partielles dans les résultats de jobs distants, y#754

    compris la correction…

    Conserver les preuves JavaScript partielles dans les résultats de jobs distants, y compris la correction en lecture seule des anciens jobs terminés, sans modifier les artefacts conservés ni les budgets de rendu. Vérifier la sauvegarde et la restauration réelles de la file via le statut authentifié, les téléchargements et l'idempotence persistante ; la fixture de récupération à deux pages reste en rendu complet dans ses budgets finis existants.

    #754 (ticket sur GitHub)
  • ModifiéFonctionneRenvoyer le code de sortie 130 sans trace lorsque SIGINT interrompt la sortie JSON

    finale, une fois le gestionnaire terminé. Les artefacts conservés restent inchangés ; un flux de sortie tronqué n'est jamais signalé comme réussi.

  • AjoutéFonctionneEnregistrer la stratégie de zone de contenu qui a produit les hachages conservés et les

    comptes de tokens…

    Enregistrer la stratégie de zone de contenu utilisée pour produire les hachages conservés et les comptes de tokens, plutôt que la stratégie de zone par défaut du parseur. Les sélecteurs explicites et les exclusions disposent désormais d'une provenance d'extraction cohérente, même lorsque le parseur de la page a utilisé sa région par défaut.

  • CorrigéFonctionneGarder les fichiers de staging SQLite natifs non publiés hors de l'historique des scans

    et de la rétention…

    Exclure de l'historique des scans et des candidats à la rétention les fichiers de staging SQLite natifs non publiés ; continuer à signaler les fichiers publiés invalides et autoriser les scans cachés ordinaires nommés par l'utilisateur.

  • AjoutéFonctionneCollecte SQLite native limitée aux sitemaps : un sitemap explicite définit la population

    d'URL complète…

    Ajout de la collecte SQLite native limitée aux sitemaps : un sitemap explicite définit l'intégralité de la population d'URL demandée, sans repli sur la page de départ, ni expansion par liens hypertextes, ni expansion vers les cibles de redirection. Les populations de sitemap vides, incomplètes ou dépassant le budget s'arrêtent explicitement, et la reprise réutilise la population conservée sans retélécharger le XML.

  • ModifiéFonctionneEnregistrements d'exécution distincts pour les captures natives simultanées et file

    partagée par projet…

    Conserver des enregistrements d'exécution distincts pour les captures natives simultanées et partager une porte d'envoi locale au projet, limitée à 2 requêtes/s, pour un même hôte public ; exposer aux observateurs le type de source, l'origine, l'empreinte de configuration et la limite de débit agrégée de chaque exécution.

  • AjoutéFonctionneRecherche littérale hors ligne sur le HEAD, le HTML, le texte du corps et le balisage

    sélectionné par CSS…

    Ajout d'une recherche littérale hors ligne sur le HEAD, le HTML, le texte du corps et le balisage sélectionné par CSS conservés, avec une couverture statique ou rendue explicite, des corps manquants marqués comme inconnus, des extraits expurgés facultatifs et une pagination vérifiée par intégrité des nouveaux paquets de résultats locaux.

  • ModifiéFonctionnePréservation des réglages propres d'un crawl Screaming Frog sauvegardé lors de l'export :

    load-crawl…

    Préserver les réglages propres d'un crawl Screaming Frog sauvegardé lors de son export : load-crawl n'injecte plus la configuration actuelle du spider. Les exécutions spider et list en direct continuent de recevoir leurs profils explicites par exécution.

6 octobre 2026

9 ajouté14 modifié9 corrigé
  • ModifiéFonctionneRésolution cohérente des hôtes virtuels loopback des tests de capture externe selon les#896

    systèmes…

    Faire résoudre de façon cohérente les hôtes virtuels loopback des tests de capture externe propres, quel que soit le système d'exploitation, sans modifier la politique réseau de production.

    #896 (ticket sur GitHub)
  • CorrigéFonctionneSaisie du terminal fonctionnelle au-delà du plafond de descripteurs de select, et#896

    protection des notes…

    Garder la saisie du terminal fonctionnelle au-delà du plafond de descripteurs de select, et empêcher Delete ou les séquences de contrôle non prises en charge d'annuler des notes non enregistrées.

    #896 (ticket sur GitHub)
  • ModifiéFonctionneConservation des événements de navigation du navigateur versionnés, avec omissions#826

    bornées, état de capture…

    Conserver les événements de navigation du navigateur versionnés, avec des omissions bornées, l'état de capture, la politique du moteur de rendu et la provenance des URL. Distinguer les redirections HTTP observées, la navigation Chromium par script, historique ou fragment, et les causes inconnues, sans affirmer de clics humains.

    #826 (ticket sur GitHub)
  • AjoutéFonctionneMêmes preuves exposées via render-check et via les rapports bornés et hors ligne de#826

    scan-navigation…

    Exposer les mêmes preuves via render-check et les rapports bornés et hors ligne de scan-navigation ; conserver les observations partielles lorsque le rendu échoue.

    #826 (ticket sur GitHub)
  • ModifiéFonctionneCompatibilité de rollback préservée en conservant les preuves de navigation dans des#826

    réglages de rendu extensibles…

    Préserver la compatibilité de rollback en conservant les preuves de navigation dans des réglages de moteur de rendu extensibles ; valider l'encodage de la préversion antérieure sans affaiblir les contrôles de provenance, et ne pas traiter les événements observés comme une politique de rendu.

    #826 (ticket sur GitHub)
  • CorrigéFonctionneGrandes populations de synthèse imbriquées, dont les histogrammes de profondeur, dans les#818

    compagnons PDF…

    Conserver les grandes populations de synthèse imbriquées, y compris les histogrammes de profondeur, dans les compagnons PDF complets, sans les imputer au budget borné des métadonnées d'affichage. Préserver les destinations nommées, les signets et les liens internes lors de la réécriture des liens portables du compagnon, en clonant le document PDF complet.

    #818 (ticket sur GitHub)
  • AjoutéFonctionneAjouter pdf_policy="overview-v1" explicite pour les requêtes PDF audit.v2 conservées.#818

    La première page distingue le nombre total de la source, le nombre affiché et le nombre omis ; les préfixes d'affichage déterministes conservent les états et raisons de couverture complets et renvoient vers le JSON d'audit complet en flux et vers les compagnons CSV des constats, des pages et du périmètre. Un manifeste de hachages et de comptes enregistre la provenance et les limites de ressources. Les destinations existantes sont refusées, les exports sont mis en zone de transit, et le marqueur d'achèvement PDF n'est publié qu'après validation de tous les compagnons obligatoires. Le comportement PDF par défaut ne change pas : l'aperçu n'est jamais sélectionné silencieusement ni présenté comme un PDF exhaustif. Voir docs/PDF_OVERVIEW.md pour les bornes exactes et la sémantique en cas d'interruption brutale.

    #818 (ticket sur GitHub)
  • AjoutéFonctionneOpération fournisseur GA4 page_views en lecture seule : vues par date, nom d'hôte et#782

    chemin visité…

    Ajout de l'opération fournisseur GA4 en lecture seule page_views, pour les comptes de vues par date, nom d'hôte et chemin visité, indépendamment des sessions sur les pages d'entrée. Réutilise les identifiants GA4 existants, le transport et le lecteur de rapports paginés avec des tentatives bornées, les issues de quota et de permission, les métadonnées explicites de fuseau horaire, d'échantillonnage et de seuil, ainsi que la liaison d'URL à l'origine déclarée. Les preuves fournisseur restreintes enregistrées se normalisent via la jointure et le pipeline BI existants ; un trafic manquant reste indisponible au lieu de devenir zéro.

    #782 (ticket sur GitHub)
  • CorrigéFonctionneRafraîchissements de l'observateur bornés : couverture par site réutilisée, activité des#777

    collecteurs…

    Garder les rafraîchissements de l'observateur bornés en réutilisant la couverture par site, en projetant séparément l'activité en direct des collecteurs et en paginant les constats audit.v2, sans matérialiser les collections du graphe non liées.

    #777 (ticket sur GitHub)
  • ModifiéFonctionneChaque collecteur actif conservé dans un historique borné, fenêtres de compteurs mesurés#777

    horodatées…

    Conserver chaque collecteur actif dans un historique borné, publier des fenêtres de compteurs mesurés horodatées et distinguer les compteurs non mesurés de zéro. Diffuser la progression vérifiée de Screaming Frog tout en bornant les deux canaux de diagnostic.

    #777 (ticket sur GitHub)
  • AjoutéFonctionnePages en lecture seule pour la checklist, le détail des tâches et les scans conservés,#777

    avec périmètre…

    Ajout de pages en lecture seule pour la checklist, le détail des tâches et les scans conservés, plus un périmètre explicite des méthodes applicables et une projection de la boîte de réception la plus récente.

    #777 (ticket sur GitHub)
  • CorrigéFonctionneExécutions de sitemap explicitement associées gardées distinctes : compteurs en cours#777

    inconnus…

    Garder distinctes les exécutions de sitemap explicitement associées : les compteurs en cours restent inconnus, et les mesures finales comptent séparément les documents sitemap analysés, les URL déclarées, les erreurs et les troncatures.

    #777 (ticket sur GitHub)
  • ModifiéFonctionneReçus d'artefacts de checklist observés via des métadonnées d'identité de fichier#777

    protégées…

    Observer les reçus d'artefacts de checklist via des métadonnées d'identité de fichier protégées, sans recalculer le hachage des octets conservés à chaque rafraîchissement. Les lectures de couverture explicites conservent la vérification des octets ; les preuves modifiées ou héritées non vérifiées restent visibles comme obsolètes ou non vérifiées.

    #777 (ticket sur GitHub)
  • CorrigéFonctionneReçus de priorité historiques liés à leur périmètre d'origine quand de nouvelles tâches#777

    sont ajoutées…

    Garder les reçus de priorité historiques liés à leur périmètre d'éléments d'origine lorsque de nouvelles tâches sont ajoutées après la préparation, et valider chaque candidat de couverture complet avant la publication atomique. Les lectures de détail concurrent limitées à un périmètre préservent la vérification passive par métadonnées seules.

    #777 (ticket sur GitHub)
  • AjoutéFonctionneComparaison explicite des audits sauvegardés, sur disque, avec résultats NDJSON complets…#762

    Ajout d'une comparaison explicite des audits sauvegardés, sur disque, avec résultats NDJSON complets, ordre déterministe, identités des sources, sommes de contrôle par fichier et conservation des constats avant et après. Les comparaisons audit.v2 volumineuses exigent un nouveau répertoire de sortie ; les identités en double et les collisions de correspondance d'URL échouent au lieu de perdre des lignes.

    #762 (ticket sur GitHub)
  • CorrigéFonctionneVérification ciblée audit.v2 bornée en présence de lignes en double, identité de scan#762

    conservée…

    Garder la vérification ciblée audit.v2 bornée lorsque des lignes en double sont présentes, conserver l'identité de scan validée dans les documents sélectionnés, et refuser les identités contradictoires ou les crawls postérieurs invalides comme preuve de correction.

    #762 (ticket sur GitHub)
  • AjoutéFonctionneCompression gzip en flux facultative pour les fichiers NDJSON compare.v2 complets…#762

    Ajout d'une compression gzip en flux facultative pour les fichiers NDJSON compare.v2 complets, avec des octets compressés déterministes, des hachages exacts des fichiers compressés et des comptes décodés de lignes et d'octets. Ajout d'un lecteur borné qui valide les exports en clair ou gzip et rejette les flux endommagés ou les comptes de manifeste qui ne correspondent pas ; la sortie en clair reste le mode par défaut.

    #762 (ticket sur GitHub)
  • CorrigéFonctionneCompatibilité de comparaison de corpus inconnue si l'un des indicateurs de complétude est#762

    absent…

    Garder la compatibilité de comparaison de corpus inconnue lorsque l'un des deux indicateurs de complétude est absent, et avertir explicitement des corpus partiels connus. Conserver les identifiants et les raisons des contrôles ignorés ou désactivés aux côtés des écarts de constats, afin que des mesures manquantes ne puissent pas être présentées comme une correction vérifiée.

    #762 (ticket sur GitHub)
  • ModifiéFonctionneObservateur de projet du terminal : navigation lisible dans les tâches, méthodes, données#752

    structurées…

    Permettre à l'observateur de projet du terminal de parcourir les détails lisibles des tâches, méthodes, données structurées, scans, exécutions, boîte de réception et preuves conservées, avec des pages bornées et une couverture de périmètre honnête. Les lectures de stockage et les soumissions explicites de notes sortent de la boucle de saisie.

    #752 (ticket sur GitHub)
  • ModifiéFonctionneBrouillons de notes et d'objectifs conservés séparément pendant une session, édition au#752

    curseur…

    Conserver séparément les brouillons de notes et d'objectifs pendant une session, prendre en charge l'édition au curseur, conserver les collages trop longs sans troncature, afficher les reçus d'enregistrement dans toutes les mises en page, et imprimer les brouillons non enregistrés après une sortie normale du terminal pour récupération.

    #752 (ticket sur GitHub)
  • AjoutéFonctionneNavigation explicite de la couverture et des artefacts du site et des concurrents, site#752

    sélectionné conservé…

    Ajouter une navigation explicite de la couverture et des artefacts du site propre et des concurrents, conserver le site sélectionné à travers les pages de scan et de constats, afficher les suggestions récentes de concurrents issues des notes, et garder visible la progression de collecte mesurée dans les terminaux compacts. Les échantillons périmés ne s'animent plus comme une progression en direct.

    #752 (ticket sur GitHub)
  • AjoutéFonctionneInventaire versionné des capacités headless généré à partir des vrais réglages du crawler…#743

    Ajout d'un inventaire versionné des capacités headless généré à partir des vrais réglages du crawler, avec des références d'implémentation, de CLI et MCP, de tests et d'écarts d'acceptation explicites.

    #743 (ticket sur GitHub)
  • AjoutéFonctionneBenchmark HTML/JavaScript optionnel sur origine propre, avec budgets figés de phase et de#743

    mémoire…

    Ajout d'un benchmark HTML/JavaScript optionnel sur origine propre, avec des budgets figés de phase, de mémoire de l'arbre de processus, de disque et de récupération. De vrais navigateurs créent les DOM mesurés ; le profil n'établit pas à lui seul la capacité JavaScript pour les très grands sites.

    #743 (ticket sur GitHub)
  • CorrigéFonctionneCorrection de l'argument de streaming non pris en charge du pont JavaScript natif et#743

    préservation…

    Corriger l'argument de streaming non pris en charge du pont JavaScript natif et préserver les compteurs de rendu déjà observés lors d'une annulation propre et d'une reprise.

    #743 (ticket sur GitHub)
  • ModifiéFonctionnelog-scan consomme les chemins de scan natifs conservés et les compagnons audit.v2 sans#711

    JSON hérité…

    Permettre à log-scan de consommer les chemins de scan natifs conservés et les compagnons audit.v2 sans matérialiser le JSON hérité. Diffuser les constats de cohérence, garder sur disque l'appartenance aux pages natives et la déduplication des constats, préserver le décompte exact des anomalies en ne limitant que les exemples. Signaler explicitement l'absence de trace native des décisions d'exclusion.

    #711 (ticket sur GitHub)
  • ModifiéFonctionneConstat lastmod de sitemap à l'échelle du site reconnu à l'origine nue du site mesuré,#711

    sans page d'accueil…

    Reconnaître un constat lastmod de sitemap à l'échelle du site, à l'origine nue du site mesuré, lorsqu'aucune page d'accueil n'a été crawlée. L'exception exige des preuves de synthèse du sitemap correspondantes et n'exempte ni les constats de pages, ni les hôtes sans rapport, ni les chemins cibles non pris en charge.

    #711 (ticket sur GitHub)
  • ModifiéFonctionneComparaison des scans audit.v2 conservés via une clé exacte et un index ordinal, sans

    duplication…

    Comparer les scans audit.v2 conservés via une clé exacte et un index ordinal, sans dupliquer les charges utiles des pages et des constats dans le stockage SQLite temporaire. Les lignes complètes, les exports déterministes en clair ou gzip, les identités des sources et les entrées héritées restent pris en charge. Les lecteurs d'audit fixent l'instantané validé via des lectures de lignes indexées.

  • ModifiéFonctionneAnnuler les sorties de comparaison en cas d'échec tardif de publication et refuser les

    destinations concurrentes…

    Annule les membres de sortie de comparaison détenus en cas d'échec tardif de publication, et refuse les destinations apparues en parallèle. Le manifeste reste le marqueur final de validation du paquet.

  • ModifiéFonctionneDécrire le point d'entrée public : ingénierie SEO configurable avec agents et liens vers

    les méthodes…

    Le point d'entrée public présente désormais l'ingénierie SEO configurable avec agents et relie chaque capacité à ses méthodes, à ses entrées et aux limites de ses preuves. Les consignes obsolètes sur le natif et SF, la couverture des projets et la remédiation sont corrigées. Le classeur développeur rédigé par les agents est documenté à part des rapports factuels, avec les critères d'acceptation revus et les liens vers les sources.

  • CorrigéFonctionneRétablir la parité du rapport humain entre les entrées audit.v2 streamées et le JSON

    d'audit équivalent…

    Le Markdown utilise désormais un seul moteur de rendu incrémental, y compris les explications des contrôles indisponibles, les enregistrements d'exclusion et les notes de couverture finales. Le XLSX partage une mise en page unique des métadonnées et écrit les constats et les pages dans des feuilles à écriture seule bornée, en conservant toutes les feuilles, colonnes, filtres, graphiques et compteurs de sources. Les constats supprimés conservés peuvent être rejoués sans matérialiser leur collection, et les URL de run manquantes utilisent le même repli sur la première page.

  • ModifiéFonctionneÉtiqueter la provenance des audits PDF indépendamment du schéma d'audit partagé : crawler

    natif…

    Les audits PDF étiquettent leur provenance indépendamment du schéma partagé : crawler natif, exports Screaming Frog ou collecteur SF explicitement identifié, et collecteur inconnu. Un audit natif utilisant le schéma SF Analyzer ne reçoit plus d'en-tête Screaming Frog.

  • ModifiéFonctionneÉcrire en flux les lignes de portée des constats supprimés en CSV au lieu de les

    accumuler…

    Les lignes de portée des constats supprimés sont écrites en CSV au fil de l'eau, sans accumuler en mémoire leurs explications rendues. Les exports complets d'exclusions conservent leur ordre et leurs faits sources, tout en gardant une allocation bornée pour de grandes collections d'exclusions conservées.

5 octobre 2026

1 modifié
  • ModifiéFonctionneRéconcilier chaque ligne de lacune de couverture à partir de sa vraie cellule Mode,#830

    valider les références…

    Chaque ligne de lacune de couverture est réconciliée à partir de sa cellule Mode réelle, les références de contrôle et d'outil couvertes sont validées contre les registres publics, et les priorités sont générées à partir des lignes non résolues.

    #830 (ticket sur GitHub)

4 octobre 2026

56 ajouté75 modifié5 corrigé
  • AjoutéFonctionneAjouter une projection hors ligne de progression GSC marque/hors marque, avec alias#880

    Unicode explicites…

    Ajout d'une projection hors ligne de la progression GSC marque/hors marque, avec alias Unicode explicites, CTR pondéré compatible et tranches de position moyenne étiquetées.

    #880 (ticket sur GitHub)
  • AjoutéFonctionneAjout d'un regroupement optionnel des tâches via check_assignment pour les URL de#878

    modèles et composants…

    Ajout d'un regroupement optionnel des tâches via check_assignment, pour les correspondances d'URL de modèles et composants déclarées ou les segments de crawl validés. Les éléments groupés conservent le nombre d'occurrences et d'URL, des preuves plafonnées, la provenance du regroupement, le périmètre de vérification et les états déclaré, candidat, confirmé ou non assigné.

    #878 (ticket sur GitHub)
  • AjoutéFonctionneAjouter des cartes de comparaison de versions url-correspondence.v1 avec origines et#877

    paires d'URL…

    Ajout, en option, de cartes de comparaison de versions url-correspondence.v1 avec origines et paires d'URL déclarées, refus des collisions, provenance des faits de page et sortie release_review.v1.

    #877 (ticket sur GitHub)
  • AjoutéFonctionneAjouter une projection hors ligne de cohortes de publication, qualifiée par preuves, avec#876

    provenance des dates…

    Ajout d'une projection hors ligne de cohortes de publication, qualifiée par les preuves : provenance des dates, inventaire des auteurs, observations étiquetées des fournisseurs et fenêtres d'âge optionnelles.

    #876 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un inventaire hors ligne des CTA et formulaires intégrés pour le HTML fourni,#875

    préservant les occurrences…

    Ajout d'un inventaire hors ligne des CTA et formulaires intégrés pour le HTML fourni, préservant les occurrences, avec cibles manquantes nullables, sorties JSON et CSV bornées et couverture explicite des corps incomplets.

    #875 (ticket sur GitHub)
  • ModifiéFonctionneConserver la classification des timeouts distants tout en masquant les erreurs de#866

    transport, et rejouer…

    Conservation de la classification des timeouts distants tout en masquant les erreurs de transport, et rejeu sûr des manifestes de proxy direct pour la vérification ciblée.

    #866 (ticket sur GitHub)
  • ModifiéFonctionneLire les preuves d'attribution dans le graphe de liens SQL conservé, préserver#866

    l'attribution nulle explicite…

    Les preuves d'attribution sont lues dans le graphe de liens SQL conservé, l'attribution nulle explicite est préservée à l'export, et les contrôles des liens externes en attente sont conservés lors de la reprise.

    #866 (ticket sur GitHub)
  • ModifiéFonctionneRégénérer les catalogues intégrés et les contrats de rapport ; installer le validateur#866

    PDF avec l'extra all…

    Régénération des catalogues intégrés et des contrats de rapport. Le validateur PDF s'installe avec l'extra « all », et les tests à faux navigateur ne dépendent plus du Chrome local sélectionné.

    #866 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un plan de chargement BigQuery optionnel et hors ligne, exposant des tables#837

    versionnées par schéma…

    Ajout d'un plan de chargement BigQuery optionnel et hors ligne, qui expose des tables versionnées par schéma, les exigences de facturation et les prérequis d'autorisation explicites, sans accès au cloud.

    #837 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un transport REST BigQuery à liste blanche, avec jobs de chargement de staging#837

    déterministes…

    Ajout d'un transport REST BigQuery à liste blanche, avec jobs de chargement de staging déterministes, réconciliation du nombre de lignes et publication atomique documentée par table, plutôt qu'une fausse transaction inter-tables.

    #837 (ticket sur GitHub)
  • ModifiéFonctionneExiger une approbation cost_authorized distincte, gérée par l'hôte, pour BigQuery avant#837

    tout jeton…

    Exige une approbation cost_authorized distincte, gérée par l'hôte, pour BigQuery, avant tout jeton, toute vérification de jeu de données ou toute écriture de staging.

    #837 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un générateur local et validé de lien de copie Looker Studio pour le pack#836

    synthétique à cinq pages…

    Ajout d'un générateur local et validé de lien de copie Looker Studio pour le pack de reporting synthétique en cinq pages. Il exige un ID de rapport d'origine et des alias de source Sheets ou BigQuery exacts, sans publier de rapport ni inventer de modèle.

    #836 (ticket sur GitHub)
  • AjoutéFonctionneAjouter la fixture synthétique de feuilles versionnée#836

    (examples/reporting-pack/worksheets/)…

    Ajout de la fixture synthétique de feuilles versionnée (examples/reporting-pack/worksheets/) : un CSV par jeu de données BI, plus le manifeste, généré de façon déterministe à l'octet près à partir de examples/audit.json et de deux entrées synthétiques GSC et GA4. Elle illustre les états suivants : zéro mesuré, supprimé ou manquant, externe seul, non rattachable, contrôle ignoré, jeu de données indisponible et quadrant incomplet. Sa reproductibilité est vérifiée par scripts/generate_reporting_pack_worksheets.py --check.

    #836 (ticket sur GitHub)
  • AjoutéFonctionneAjouter examples/reporting-pack/SETUP.md : le guide mécanique côté propriétaire pour#836

    importer…

    Ajout de examples/reporting-pack/SETUP.md : le guide mécanique, côté propriétaire, pour importer les six feuilles dans Google Sheets, relier les alias de sources de données réservés, construire les cinq pages du blueprint avec les contrôles et champs calculés déclarés, activer l'autorisation de copie et vérifier une copie neuve. Le modèle Looker Studio natif reste une étape externe, à autoriser par le propriétaire. Aucun ID de rapport, lien ni écriture Google n'est inclus.

    #836 (ticket sur GitHub)
  • ModifiéFonctionneConserver les noms de partitions, les compteurs et les sommes de contrôle du paquet BI#836

    généré, afin que la fixture…

    Le paquet BI généré conserve désormais ses noms de partitions, ses compteurs et ses sommes de contrôle, pour que la fixture de feuilles passe le contrôle préalable Sheets existant et les consommateurs d'export filtré. Les champs d'alias de l'API Linking sont documentés séparément, et la vérification d'une copie neuve via l'URL générée est exigée, sans réparation manuelle des sources.

    #836 (ticket sur GitHub)
  • ModifiéFonctionneRejeter les alias d'API Linking en double après normalisation des espaces et renvoyer les#836

    alias exacts…

    Rejet des alias d'API Linking en double après normalisation des espaces, et renvoi des alias exacts utilisés dans les paramètres d'URL. Définition d'identifiants de champs d'exécution partagés, de contrôles de date fournisseur groupés et de graphiques de couverture qui excluent les populations qui se chevauchent. La création du modèle natif et la vérification d'une copie neuve restent des exigences d'acceptation externes.

    #836 (ticket sur GitHub)
  • AjoutéFonctionneAjouter des lignes de cohortes d'URL explicites et qualifiées par preuves aux paquets BI#835

    locaux, y compris…

    Ajout de lignes de cohortes d'URL explicites et qualifiées par preuves aux paquets BI locaux, y compris des quadrants Search Console et GA4 sûrs pour les zéros mesurés, uniquement pour des observations complètes, compatibles et un-à-un.

    #835 (ticket sur GitHub)
  • ModifiéFonctionneCalculer les parts observées de liens entrants à partir des pages liantes uniques du#835

    périmètre…

    Calcul des parts observées de liens entrants à partir des pages liantes uniques du périmètre, avec extraction HTML terminée. Les occurrences répétées sont conservées séparément et les populations partielles sont étiquetées.

    #835 (ticket sur GitHub)
  • AjoutéFonctionneAjouter des paquets BI hors ligne, typés et déterministes pour les scans, audits et#834

    preuves fournisseurs…

    Ajout de paquets BI hors ligne, typés et déterministes, pour les scans et audits enregistrés et les preuves fournies par les fournisseurs, avec bornes de partitions, états nuls, conservation des lignes et cellules CSV protégées contre l'injection de formules.

    #834 (ticket sur GitHub)
  • ModifiéFonctionnePréserver les constats des fichiers compagnons audit.v2 bornés, joindre jusqu'à 1 000 000#834

    d'URL de scan…

    Conservation des constats issus des fichiers compagnons audit.v2 bornés, jointure de jusqu'à 1 000 000 d'URL de scan conservées via un artefact SQLite durable de preuves, et diffusion de cet artefact vers BI sans matérialiser les listes de pages ni d'URL correspondantes. Cela ne livre pas de modèle Looker Studio copiable.

    #834 (ticket sur GitHub)
  • ModifiéFonctionneProjeter les groupes de constats, les candidats de quadrants fournisseurs et les sources#834

    de liens entrants…

    Projection des groupes de constats, des candidats de quadrants fournisseurs et des sources de liens entrants éligibles, via un index SQLite jetable et borné. Les dimensions dynamiques fournisseurs restent valides dans les exports sélectionnés et dans les plans hors ligne Sheets et BigQuery. Le nombre de partitions et la consommation disque sont bornés.

    #834 (ticket sur GitHub)
  • ModifiéFonctionnePréserver les URL cibles et messages des constats d'audit natifs comme colonnes BI typées…#834

    Les URL cibles et messages des constats d'audit natifs sont désormais des colonnes BI typées, et non plus seulement présents dans le JSON source conservé. Les sélections d'URL exactes conservent ainsi les constats concernés.

    #834 (ticket sur GitHub)
  • AjoutéFonctionneAjouter scan-fragment-links (seo_scan_fragment_links) et le contrôle d'audit#827

    BROKEN_BOOKMARK…

    Ajout de scan-fragment-links (seo_scan_fragment_links) et du contrôle d'audit BROKEN_BOOKMARK : chaque <a href> avec fragment, dans le HTML ou DOM complet conservé, est résolu contre les id d'éléments et les cibles <a name> du document de destination, selon l'algorithme WHATWG de défilement vers le fragment. Le fragment sérialisé est d'abord comparé aux id et aux noms, puis la valeur décodée en pourcentage et en UTF-8 est comparée aux deux. + reste un plus littéral, et # ou #top renvoient au haut du document. Les représentations statique, rendue et de fragment hérité sont évaluées séparément, les règles de redirection et de <base href> sont respectées, et une chaîne de requête différente désigne un autre document. Les corps manquants, tronqués, non pris en charge, en échec ou épuisés par le budget sont signalés comme des ignorés nommés, jamais comme des constats d'erreur. Les exports Screaming Frog et les imports hérités indiquent le contrôle comme indisponible, au lieu de prétendre qu'il s'est bien déroulé. Les résultats sont bornés et paginés de façon déterministe (total, returned, offset/limit, next_offset, état de couverture), identiques via la CLI, le MCP et le résumé d'audit des scans conservés. Rien n'est récupéré : l'évaluation est en lecture seule et hors ligne.

    #827 (ticket sur GitHub)
  • ModifiéFonctionneValider les liens de retour hreflang natifs par rapport aux déclarations cibles#825

    conservées complètes…

    Validation des liens de retour hreflang natifs par rapport aux déclarations cibles conservées complètes, en distinguant un retour manquant avéré d'une cible non explorée ou dont le corps est indisponible. Signalement des alternatives noindex observées, conservation des libellés bruts et des identités d'URL normalisées avec contexte de doublon ou de conflit, et marquage des relations de population partielle comme non mesurées. Les surfaces d'audit, CLI, MCP et rapport existantes portent les mêmes constats, sans récupération supplémentaire.

    #825 (ticket sur GitHub)
  • AjoutéFonctionneAjouter CANONICAL_TARGET_ERROR pour signaler les cibles canonical récupérées en 4xx/5xx…#824

    Ajout de CANONICAL_TARGET_ERROR pour signaler les cibles canonical récupérées qui renvoient un 4xx ou un 5xx, avec preuves de la source, de la cible, de la réponse et de l'indexabilité. Les cibles inconnues ou au statut incomplet restent indisponibles. Les variantes 2xx connues lèvent le verdict d'erreur, et les cibles 3xx restent sous CANONICAL_TO_REDIRECT.

    #824 (ticket sur GitHub)
  • AjoutéFonctionneAjouter CANONICAL_HOMEPAGE_GROUP pour les groupes d'au moins trois pages indexables#824

    récupérées…

    Ajout de CANONICAL_HOMEPAGE_GROUP pour les groupes d'au moins trois pages récupérées et indexables, réparties sur au moins deux sections de chemin, avec des titres et H1 distincts, et qui se canonicalisent vers la page d'accueil récupérée. Les pages d'accueil auto-référencées, les URL avec requête, la pagination reconnaissable, les motifs de pagination ou de filtre configurés, les preuves d'accueil incomplètes et les crawls natifs partiels ne produisent aucun constat à l'échelle du site.

    #824 (ticket sur GitHub)
  • AjoutéFonctionneAjouter des preuves objectives d'auteur, de date et de pages de confiance aux audits#823

    ciblés (issue #823)…

    Ajout de preuves objectives sur l'auteur, les dates et les pages de confiance aux audits ciblés (issue #823) : huit contrôles de gravité « notice » dans seohead/sf/core/eeat.py, qui signalent ce qu'un crawl peut observer, et jamais un score E-E-A-T. NO_AUTHOR_BYLINE et NO_CONTENT_DATES ne se déclenchent que sur les pages de type contenu (type d'article JSON-LD, og:type=article, élément <article> ou chemin de contenu conventionnel). Ils nomment les porteurs lus (meta_author, rel_author, itemprop=author, classe byline, <time datetime>, author/datePublished/dateModified en JSON-LD, chemin d'URL de type date), chacun avec une confiance déclarée. MISSING_ABOUT_PAGE, MISSING_CONTACT_PAGE, MISSING_PRIVACY_POLICY et MISSING_TERMS_PAGE renvoient l'un de ces états : found_indexable (silencieux), found_non_indexable, found_error, discovered_not_crawled ou not_discovered. Ainsi, une page qui existe sans être servie ne se lit jamais comme une page que personne n'a liée. FEW_CITATIONS ne signale que ce que les positions des liens permettent de prouver : un lien sortant dans le corps du texte, ou un compte déclaré à zéro. YMYL_REVIEW_CANDIDATE signale les correspondances déterministes de mots entiers dans le chemin ou le titre, pour relecture humaine, jamais une classification. Le non-mesuré reste distinct de l'absent à tous les niveaux : une page dont le corps n'a jamais été analysé garde trust_signals à NULL et est comptée dans la raison d'ignorance. summary.trust_evidence enregistre le périmètre évalué, l'état des pages par type et une mise en garde de crawl partiel pour les verdicts not_discovered.

    #823 (ticket sur GitHub)
  • ModifiéFonctionneClasser les p75 de terrain CrUX de la fenêtre actuelle (LCP, INP, CLS) selon des seuils#822

    officiels versionnés…

    Classement des p75 de terrain CrUX de la fenêtre actuelle (LCP, INP et CLS) selon des seuils officiels versionnés, en conservant la portée URL ou origine, le facteur de forme et la période de collecte. Les preuves de terrain manquantes, incomplètes ou en échec restent indisponibles ou partielles.

    #822 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un échantillonnage d'URL explicite et borné avec cache privé optionnel, et#822

    accepter les preuves CrUX…

    Ajout d'un échantillonnage d'URL explicite et borné, avec cache privé optionnel, et acceptation des preuves CrUX enregistrées dans les audits et rapports de site, sans requête automatique vers le fournisseur. Les octets de réponse et de cache sont bornés. Les nombres d'échantillons enregistrés incohérents et les enregistrements d'URL répétés sont rejetés, au lieu d'afficher une couverture de terrain complète.

    #822 (ticket sur GitHub)
  • ModifiéFonctionneDocumenter la frontière du CLI Docker one-shot, séparément du service API distant et#820

    worker optionnel

    Documentation de la frontière actuelle du CLI Docker en mode one-shot, séparée du service API distant et du worker optionnel, construits explicitement.

    #820 (ticket sur GitHub)
  • AjoutéFonctionneAjouter la recette d'exécution SSH à espace de travail persistant, et expliquer que#820

    l'état de sortie du CLI…

    Ajout de la recette d'exécution SSH à espace de travail persistant, et explication que l'état de sortie et les artefacts du CLI ne constituent pas une vérification de santé de service HTTP.

    #820 (ticket sur GitHub)
  • ModifiéFonctionneAdmettre les configurations explicites de crawl natif SQLite jusqu'à 1 000 000 d'URL,#818

    avec un budget distinct…

    Admission des configurations explicites de crawl natif SQLite jusqu'à 1 000 000 d'URL, avec un budget distinct de 2 000 000 de requêtes HTTP et le profil synthétique existant, limité au stockage. La CLI, le MCP, la file distante et les workers respectent les mêmes budgets déclarés. Les API matérialisées héritées (legacy et listes) conservent une borne de sécurité explicite de 50 000 URL. Les robots de liste, les nouvelles tentatives, les redirections et les sauts canoniques partagent désormais leur budget de requêtes. Les audits natifs et la réanalyse hors ligne passent par le chemin audit.v2 borné, sans l'ancien refus de pont à 10 000 pages ou 20 000 formulaires. Les compteurs du writer transactionnel évitent de rescanner la frontière croissante à chaque lot. Un pilote d'acceptation manuel enregistre les identités sources chargées, l'interruption et la reprise, ainsi que les consommateurs en aval. L'admission n'est pas en soi la preuve d'une acceptation complète du million d'URL.

    #818 (ticket sur GitHub)
  • ModifiéFonctionneExécuter chaque étape d'acceptation native manuelle sous un surveillant de ressources de#818

    sous-processus…

    Chaque étape d'acceptation native manuelle s'exécute sous un surveillant de ressources de sous-processus, conserve les artefacts interrompus, vérifie chaque ligne et la couverture des tâches en CSV et XLSX, et exerce séparément le HTTP en boucle locale détenue et protégée, avec un rythme par défaut inchangé.

    #818 (ticket sur GitHub)
  • ModifiéFonctionneAutoriser des durées de crawl distant explicitement permises allant jusqu'à 14 jours, en#818

    conservant l'heure par défaut…

    Autorisation de durées de crawl distant explicitement permises jusqu'à 14 jours, en conservant le délai par défaut d'une heure et les budgets indépendants de projet, de requêtes, de disque, de bail et de rendu. Une cible d'un million de pages peut ainsi tenir dans son débit de requêtes poli inchangé. Les valeurs au-delà du plafond de durée et les types invalides échouent avant toute collecte.

    #818 (ticket sur GitHub)
  • ModifiéFonctionneLa réanalyse hors ligne utilise une échéance propre à chaque opération SQLite execute et#818

    fetch. L'interruption et l'annulation des requêtes sont préservées, sans imputer à l'échéance initiale de validation d'ouverture du scan le temps d'analyse Python ni les écritures dérivées.

    #818 (ticket sur GitHub)
  • ModifiéFonctionnecrawl-site --out-dir hérité conserve désormais les preuves de pages, liens et#817

    formulaires dans des JSONL annexes…

    Le mode hérité crawl-site --out-dir conserve désormais les preuves de pages, liens et formulaires dans des fichiers JSONL annexes en ajout seul, pendant la collecte et la reprise, au lieu de garder des listes dupliquées en mémoire. Les points de contrôle vérifient les compteurs des annexes. Les anciens points de contrôle v4 à formulaires inline migrent sans perdre les constats de formulaires. Le pont d'audit existant nomme ses bornes de matérialisation pages, formulaires et liens, et préserve les preuves collectées lorsqu'un audit est indisponible. Un rapport antérieur est conservé sous un nom de fichier obsolète, au lieu d'être présenté comme le run courant. L'escalade JavaScript native lit les enregistrements de pages via une vue SQLite réitérable, au lieu de reconstruire tous les objets de pages. Le streaming complet des gros audits reste suivi dans #816 et #817.

    #817 (ticket sur GitHub)
  • ModifiéFonctionneStocker les audits natifs trop volumineux dans des fichiers compagnons audit.v2 ordonnés…#817

    Stockage des audits natifs trop volumineux dans des fichiers compagnons audit.v2 ordonnés, au lieu d'abandonner la disponibilité de l'audit.

    #817 (ticket sur GitHub)
  • ModifiéFonctionneDiffuser la normalisation des audits natifs dans leur contexte, sans liste intermédiaire#817

    d'enregistrements.

    #817 (ticket sur GitHub)
  • CorrigéFonctionneConserver les cartes de pages d'audit natif et les métriques dérivées par page dans un#817

    contexte SQLite temporaire…

    Conservation des cartes de pages d'audit natif et des métriques dérivées par page dans un magasin de contexte SQLite temporaire.

    #817 (ticket sur GitHub)
  • CorrigéFonctionneConserver les constats natifs sur disque jusqu'à ce que l'agrégation ordonnée attribue#817

    leurs identifiants de rapport.

    #817 (ticket sur GitHub)
  • CorrigéFonctionneConserver les groupes natifs de doublons et de contenu dans un stockage SQLite ordonné#817

    pendant l'analyse.

    #817 (ticket sur GitHub)
  • ModifiéFonctionneBorner les recherches de pages répétées, regrouper les backlinks des constats et résoudre#817

    les profondeurs de découverte native…

    Bornage des recherches de pages répétées, regroupement des backlinks des constats et résolution des profondeurs de découverte native, sans reconstruire chaque route ni charger chaque nœud en Python. Les routes longues conservent leur profondeur exacte et leurs extrémités tronquées explicites.

    #817 (ticket sur GitHub)
  • ModifiéFonctionneDiffuser les entrées de pages natives conservées et les recherches d'inlinks avant la#817

    construction du contexte.

    Les relations de corpus et hreflang non vides sont dérivées via des index adossés au disque, les collections de preuves complètes sont conservées dans audit.v2, et les échantillons bornés de constats de relation sont étiquetés avec leurs nombres exacts d'occurrences.

    #817 (ticket sur GitHub)
  • ModifiéFonctionneBorner le cache de pages par octets Python décodés estimés, en plus du nombre d'entrées…#817

    Le cache de pages est borné par les octets Python décodés estimés, en plus du nombre d'entrées. Les pages surdimensionnées non mises en cache restent lisibles, et les mutations invalident leur ancien poids. Les rangs de taille HTML sont conservés sous forme de paires scalaires stables URL et taille, au lieu de garder chaque modèle de page complet. Le JSON sérialisé des pages n'est plus conservé dans les callbacks de mutation.

    #817 (ticket sur GitHub)
  • ModifiéFonctionneNe conserver que les faits scalaires (URL, statut, indexabilité, canonical, redirection)#817

    pendant la vérification…

    Seuls les faits scalaires d'URL, de statut, d'indexabilité, de canonical et de redirection sont conservés pendant la vérification des paires avec et sans slash final. Les connexions SQLite des adaptateurs durables et des jobs distants sont fermées explicitement.

    #817 (ticket sur GitHub)
  • ModifiéFonctionneDiffuser les compteurs de couverture des corps indisponibles et du charset, conserver#817

    l'état scalaire des pages de confiance…

    Les compteurs de couverture des corps indisponibles et du charset sont diffusés. L'état scalaire de sélection des pages de confiance est conservé au lieu des populations de pages candidates, et les correspondances DOM sur le HTML stocké sont traitées en deux passes sur l'index de fichiers fixe. L'ordre des représentants des variantes normalisées, les exemples d'URL existants, la couverture complète des sources correspondantes et chaque constat sont préservés.

    #817 (ticket sur GitHub)
  • ModifiéFonctionneValider ligne par ligne le JSONL des points de contrôle de crawl hérités avant ajout, en#817

    refusant les preuves…

    Le JSONL des points de contrôle de crawl hérités est validé ligne par ligne avant ajout : les preuves manquantes, corrompues ou non terminées sont refusées sans être remplacées. Les anciens points de contrôle à formulaires inline sont comparés à leur annexe, sans allouer une seconde liste de formulaires.

    #817 (ticket sur GitHub)
  • AjoutéFonctionneAjouter une reprise de benchmark JavaScript avec provenance vérifiée entre les paires#817

    terminées…

    Ajout d'une reprise de benchmark JavaScript avec provenance vérifiée entre les paires terminées, en préservant les reçus antérieurs et les budgets disque. Les cas interrompus restent des bloquants explicites. Un cas de benchmark n'est marqué réussi qu'après une requête ou réanalyse réussie et des preuves CSV de pages complètes.

    #817 (ticket sur GitHub)
  • ModifiéFonctionneConserver les listes d'URL explicites avec le writer SQLite natif, en préservant l'ordre#817

    d'entrée exact…

    Les listes d'URL explicites sont conservées avec le writer SQLite natif, en respectant l'ordre d'entrée exact, plusieurs hôtes et la sémantique sans découverte. L'entrée par fichier d'échange est diffusée, les budgets de requêtes et de temps sont préservés lors de la reprise de collecte, les réponses bornées et les preuves de sauts sont conservées, et les contrôles graphe et formulaires restent explicitement indisponibles. Les grandes listes de répertoires utilisent le même spool, avec un pont JSON d'audit séparément borné.

    #817 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un fichier compagnon SQLite audit.v2 versionné pour les collections d'audit#816

    ordonnées au-delà du plafond JSON…

    Ajout d'un fichier compagnon SQLite audit.v2 versionné pour les collections d'audit ordonnées complètes, au-delà du plafond de taille JSON inline, avec liaison à la provenance du scan et validation d'intégrité de bout en bout.

    #816 (ticket sur GitHub)
  • ModifiéFonctionneDiffuser les rapports audit.v2 en JSON, CSV, XLSX, Markdown et DOCX, comparer les#816

    constats de gravité élevée…

    Les rapports audit.v2 sont diffusés en JSON, CSV, XLSX, Markdown et DOCX. Les populations de constats de gravité élevée sont comparées, et les opérations snapshot et prune restent appariées au fichier compagnon, tout en préservant le schéma scan.v1.

    #816 (ticket sur GitHub)
  • ModifiéFonctionneConserver une seule fois les grandes appartenances ordonnées aux groupes dans audit.v2#816

    révision 3 et le registre révision 5…

    Les grandes appartenances ordonnées aux groupes sont conservées une seule fois dans le stockage audit.v2 révision 3 et le registre révision 5, avec lecture rétrocompatible des audits, migration atomique du registre, pagination explicite des membres via CLI et MCP, et compagnons BI d'appartenance complets et liés à leur source.

    #816 (ticket sur GitHub)
  • ModifiéFonctionnePréserver le digest audit.v2 source lors de la réanalyse hors ligne ; persister la portée#816

    incomplète du registre…

    Le digest audit.v2 source est préservé lors de la réanalyse hors ligne. La portée incomplète des groupes du registre est persistée, et les ressources d'ingestion sont fermées en cas d'échec de validation.

    #816 (ticket sur GitHub)
  • ModifiéFonctionneRéutiliser le résumé exact de capacité du corpus pendant qu'un scan natif sans#815

    métadonnées n'a aucune preuve…

    Réutilisation du résumé exact de capacité du corpus lorsqu'un scan natif en métadonnées seules ne contient aucune preuve de réponse, de document, de corps ou de ressource. Cela évite des lectures répétées de tout le corpus à chaque validation de page clairsemée, sans modifier le stockage du scan.

    #815 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un profileur de capacité des scans natifs, hors ligne et sur option…#815

    Ajoute, sur option et hors ligne, un profileur de capacité des scans natifs : liens, HTML conservé et DOM rendu sont dimensionnés indépendamment, avec des budgets de ressources explicites et un exercice de perte de processus et de reprise. Il présente la limite existante de 50 000 URL à l'admission et la finalisation incomplète comme des preuves bloquées, et non comme une capacité.

    #815 (ticket sur GitHub)
  • ModifiéFonctionneNommer l'annulation d'une requête navigateur épinglée render_cancelled et fermer…#811

    Nomme l'annulation d'une requête navigateur épinglée render_cancelled et ferme le contexte distant isolé ainsi que le navigateur en cas d'annulation ou de déconnexion, sans repli sur le local.

    #811 (ticket sur GitHub)
  • ModifiéFonctionneAutoriser une configuration de projet distante de confiance à fournir des références#810

    d'identifiants…

    Permet à une configuration de projet distante de confiance de fournir des références d'identifiants d'environnement liées à l'hôte, avec une provenance conservée et masquée, et un échec avant toute collecte si une référence est indisponible.

    #810 (ticket sur GitHub)
  • ModifiéFonctionneAutoriser un transport Playwright distant, géré par le service et vérifié en version,#809

    pour un projet en file…

    Autorise, pour un projet en file d'attente, un transport Playwright distant géré par le service et dont la version est contrôlée. L'adresse du point d'accès reste hors des soumissions, et les requêtes navigateur épinglées et soumises à la politique restent en vigueur.

    #809 (ticket sur GitHub)
  • AjoutéFonctionneExposer les chemins observés d'un scan enregistré, les liens entrants inverses et le#807

    contexte des occurrences…

    Expose les chemins observés d'un scan enregistré, les liens entrants inverses et le contexte des occurrences par une requête CLI/MCP partagée, bornée et en lecture seule, avec une identité de scan explicite et des résultats d'erreur.

    #807 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un positionnement des liens par occurrence, borné et en lecture seule, et le#806

    contexte du titre le plus proche…

    Ajoute un positionnement des liens par occurrence, borné et en lecture seule, ainsi que le contexte du titre le plus proche, à partir du HTML statique conservé et du DOM rendu. Les identifiants de liens en double sont préservés, et les données indisponibles ou partielles sont signalées explicitement.

    #806 (ticket sur GitHub)
  • AjoutéFonctionneNouvelle commande semantic-inputs (seo_semantic_inputs via MCP) qui construit le#801

    manifeste des entrées…

    Nouvelle commande semantic-inputs (seo_semantic_inputs via MCP) qui construit le manifeste reproductible des entrées normalisées utilisé par le travail de similarité sémantique. Pour chaque document, elle enregistre le hash du corps conservé, le hash exact de l'entrée décodée, le hash de la sortie normalisée, la stratégie de zone de contenu et les indices de langue (le <html lang> de la page et la part des scripts de lettres), mais jamais le texte normalisé lui-même. --scan diffuse hors ligne les corps complets conservés selon la configuration de zone de contenu enregistrée pour le crawl, sans nouvelle requête. Un corps manquant ou partiel reste une omission explicite et ne donne jamais un résultat vide propre (#801).

    #801 (ticket sur GitHub)
  • ModifiéFonctionneValider le nombre de pages, la taille, le texte extractible du PDF d'audit technique et#800

    la conservation du modèle…

    Valide le nombre de pages, la taille en octets, le texte extractible et la conservation des enregistrements du modèle source du PDF d'audit technique avant publication d'un rapport généré.

    #800 (ticket sur GitHub)
  • AjoutéFonctionneAjouter une sortie PDF Chromium bilingue hors ligne aux chemins CLI et MCP partagés de#799

    génération de rapports…

    Ajoute une sortie PDF Chromium bilingue, hors ligne, aux chemins CLI et MCP partagés de génération de rapports. Le fichier temporaire est validé et nettoyé avant son remplacement atomique.

    #799 (ticket sur GitHub)
  • AjoutéFonctionneAjouter des mises en page PDF d'audit technique autonomes, en anglais et en russe, avec#798

    des jetons de marque neutres…

    Ajoute des mises en page PDF d'audit technique autonomes, en anglais et en russe, avec des jetons de marque neutres, des graphiques de gravité et de couverture, des états explicites de run incomplet et un enchaînement de pages pour les contenus longs.

    #798 (ticket sur GitHub)
  • CorrigéFonctionneSéparer la mise en page PDF de la construction du modèle d'audit et de l'intégration#798

    CLI/MCP.

    #798 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un modèle de contenu PDF d'audit technique versionné et hors ligne, qui préserve#797

    les enregistrements source…

    Ajoute un modèle de contenu PDF d'audit technique versionné et hors ligne, qui préserve les enregistrements source, les compteurs exacts source et projetés, le périmètre et les états de couverture pour les deux contrats d'audit pris en charge.

    #797 (ticket sur GitHub)
  • ModifiéFonctionnePersister les versions enregistrées des scénarios de workflow, le contexte du site et des#796

    concurrents, les preuves par étape…

    Persiste les versions enregistrées des scénarios de workflow, le contexte du site et des concurrents, les preuves par étape et les points de validation. Une exécution interrompue peut être reprise par une session locale ultérieure, mais seulement si ses dépendances actuelles restent valides.

    #796 (ticket sur GitHub)
  • ModifiéFonctionneExiger une liste de travail du contrôleur pour lancer un workflow et conserver les#796

    accusés de tri des notes de spécialiste…

    Exige une liste de travail du contrôleur pour lancer un workflow, et conserve les accusés de tri explicites des notes de spécialiste pour les résultats tâche, objectif, concurrent, bloqué ou rejeté.

    #796 (ticket sur GitHub)
  • ModifiéFonctionneExiger que les points de contrôle réussis du workflow vérifient les octets des artefacts#796

    conservés liés au projet…

    Exige que les points de contrôle réussis du workflow vérifient les octets des artefacts conservés, liés au projet, par rapport à leurs reçus SHA-256. Des preuves manquantes ou modifiées rendent une exécution antérieure obsolète, sans réécrire l'historique. Les budgets de vérification ne certifient jamais silencieusement une preuve et ne suppriment jamais son reçu.

    #796 (ticket sur GitHub)
  • ModifiéFonctionneAutoriser des profils de politique de hachage des preuves explicites et bornés, tout en#796

    normalisant les anciennes politiques.

    L'observation passive du workflow vérifie les métadonnées de vérification conservées sans recalculer le hash des artefacts. Les reçus modifiés ou non vérifiés restent explicites.

    #796 (ticket sur GitHub)
  • AjoutéFonctionneAjouter une commande CLI project progress bornée et paginée, et l'outil MCP#795

    seo_project_progress…

    Ajoute une commande CLI project progress bornée et paginée, ainsi que l'outil MCP seo_project_progress, avec le nombre d'éléments par état de checklist et les prochaines actions réalisables. La vue réutilise les résultats de couverture scopés et n'affiche un pourcentage d'achèvement des tâches d'audit, clairement libellé, que si chaque site inclus dispose d'un plan convenu et d'un dénominateur de tâches mesuré et non vide. La couverture de la population d'URL reste séparée.

    #795 (ticket sur GitHub)
  • ModifiéFonctionneLes checklists de projet peuvent désormais enregistrer le périmètre d'audit convenu et#794

    afficher des ratios de couverture honnêtes (#794). project-checklist-init / seo_project_checklist_init acceptent un plan facultatif : un relecteur, une population d'URL déclarée comme complete_set, un sample nommé ou unknown, avec sa source, sa size ou ses urls énumérées, et des populations templates facultatives par gabarit, ainsi qu'un accord tasks facultatif (all_agreed, ou une selection sourcée d'identifiants d'éléments de checklist existants). Le plan est lié à l'identité du site du projet et estampillé avec la révision d'écriture. Enregistrer un plan fait passer la checklist au format seohead.coverage.v3 et ajoute une entrée à l'historique de plans conservé. Réenregistrer un accord identique est une opération idempotente sans effet ; un accord modifié marque les preuves antérieures comme obsolètes au lieu de les réévaluer avec un dénominateur changé. Les documents v3 à plan unique migrent à la lecture. La lecture, la réconciliation ou l'application de priorités n'améliore jamais une population et n'en invente jamais une, et les documents v1 et v2 continuent à se charger sans changement. Les éléments hors sélection sont signalés not_agreed, visibles en dehors de tous les dénominateurs.

    #794 (ticket sur GitHub)
  • ModifiéFonctionneLa complétion de checklist suit désormais le périmètre mesuré : un élément automatique#794

    limité au site…

    La complétion de checklist suit désormais le périmètre mesuré. Un élément automatique limité au site, appuyé sur une mesure partielle (scan partiel), reste inachevé au lieu d'être compté comme terminé, tandis qu'un élément limité à des URL d'échantillon explicites se termine toujours lorsque l'artefact couvre exactement ce périmètre. L'indicateur complete de premier niveau signifie désormais que l'audit scopé est terminé : chaque tâche convenue applicable est faite, aucune exclusion n'est en attente et la population d'URL convenue est entièrement couverte par des mesures vérifiées. Ainsi, un périmètre inconnu ou non mesuré ne peut jamais signaler un audit terminé.

    #794 (ticket sur GitHub)
  • ModifiéFonctionneLe statut de checklist renvoie désormais coverage : cinq ratios distincts —#794

    audit_tasks, checks…

    Le statut de checklist renvoie désormais coverage : cinq ratios distincts (audit_tasks, checks avec measured_urls, manual_review, deliverable_review et url_population), chacun avec sa propre basis, son numerator, son denominator et son state. Un nombre d'URL n'est donc jamais mélangé à un compte de contrôles ou de tâches. Un dénominateur non justifiable reste null avec state: "unknown" et une raison, au lieu de devenir 0/0 ou 100 %. Les mesures qui ne peuvent pas être vérifiées par rapport à la population convenue maintiennent l'axe URL en partial et ne comptent que les URL éligibles vérifiées. L'appartenance aux URL est vérifiée contre l'énumération convenue : une population déclarée uniquement par size ne compte aucune URL mesurée, et le numérateur ne peut jamais dépasser son dénominateur. Les populations par gabarit sont validées comme sous-populations convenues de la population du site lors de l'enregistrement ou de la lecture d'un plan : les URL énumérées d'un gabarit doivent appartenir à l'ensemble de sites énuméré, et l'appartenance déclarée à un gabarit ne peut pas dépasser la taille convenue du site. Un plan incohérent est donc refusé, et non tronqué ni compté au-delà du dénominateur. Les preuves de contrôle enregistrées portent désormais l'énumération des URL mesurées, de sorte que le numérateur d'URL est un ensemble vérifiable et non un nombre de lignes. L'agrégation multi-sites additionne les axes par site et passe à unknown dès qu'un site ne peut pas justifier son dénominateur.

    #794 (ticket sur GitHub)
  • ModifiéFonctionneUn enregistrement not_applicable devient une exclusion examinée : il exige une raison,#794

    un relecteur…

    Un enregistrement not_applicable est désormais une exclusion examinée : il exige une raison, un relecteur et une base de preuve inspectable, soit un artifact relatif au projet avec digest, soit une référence evidence explicite. Les exclusions examinées conservent leur identifiant stable et leur historique, ne sortent des dénominateurs de tâches que par la décision enregistrée et sont listées à part sous exclusions. Un élément désactivé, un enregistrement d'exclusion périmé ou un enregistrement not_applicable hérité, écrit avant la règle de base de preuve, reste dans le dénominateur en tant que pending_exclusion jusqu'à un nouvel examen. Ainsi, la désactivation, le retrait du catalogue ou le reclassement ne peuvent jamais réduire silencieusement les comptes convenus. Une exclusion examinée et récente sur un élément retiré du catalogue se résout normalement, au lieu de rester en attente indéfiniment.

    #794 (ticket sur GitHub)
  • AjoutéFonctionneAjouter le prompt workflow/full-audit-v1 et le scénario full-audit via le catalogue#793

    existant…

    Ajoute le prompt adressable workflow/full-audit-v1 et le scénario full-audit via les routes de catalogue existantes des compétences et des scénarios, en CLI comme en MCP. Le workflow réutilise les chemins de collecte et de méthode déjà livrés, conditionne la vérification et le reporting aux preuves réelles, et sépare la préparation du projet de la complétion de l'audit complet.

    #793 (ticket sur GitHub)
  • ModifiéFonctionneLier les décisions de remédiation à des artefacts de vérification immuables et aux hash#792

    avant/après exacts…

    Lie les décisions de remédiation à des artefacts de vérification immuables et aux hash exacts des preuves avant et après, y compris pour les bases de référence audit.v2 diffusées en flux.

    #792 (ticket sur GitHub)
  • ModifiéFonctionnePrésenter les résultats de remédiation conservés avec les états de couverture#791

    « représentée » et « périmètre complet »…

    Présente les résultats de remédiation conservés avec les états de couverture « représentée » et « périmètre complet », des dénominateurs par tâche et des pages de cas bornées pour les grands registres.

    #791 (ticket sur GitHub)
  • AjoutéFonctionneAjouter des contrôles de remédiation bornés, indexés par ledger, qui réutilisent le#790

    vérificateur protégé…

    Ajoute des contrôles de remédiation bornés, indexés par ledger, qui réutilisent le vérificateur protégé, diffusent les sélections audit.v2 et refusent toute dérive de périmètre.

    #790 (ticket sur GitHub)
  • ModifiéFonctionneLier la vérification de remédiation à l'identité d'audit conservée et à la politique#790

    d'origine…

    Lie la vérification de remédiation à l'identité d'audit conservée et à la politique d'origine qui affecte les résultats. Un UUID de scan réutilisé ne suffit plus à résoudre un ancien cas.

    #790 (ticket sur GitHub)
  • AjoutéFonctionneAjout du ledger ledger.v1 de remédiation (seohead.storage.ledger, identifiant#788

    d'application SEOL)…

    Ajout du ledger de remédiation ledger.v1 (seohead.storage.ledger, identifiant d'application SEOL) : un artefact SQLite distinct, lié au projet, qui enregistre les constats, l'identité de chaque occurrence, l'appartenance aux URL concernées et un historique d'observations en ajout seul, à partir d'audits scan.v1 et scan.v2 validés, sans modifier les scans sources. L'ingestion lie chaque source par UUID de scan, plus révision des preuves, digest d'audit et identité du producteur et de la configuration. Les rejeux exacts sont idempotents, les octets contradictoires sous une même révision sont refusés de façon atomique, et la couverture capped ou aggregate_only ainsi que les preuves unavailable sont conservées comme données, sans être traitées silencieusement comme résolues. Inclut une migration transactionnelle 0→1, une validation complète du schéma et de l'intégrité à l'ouverture, et docs/LEDGER.md (#788).

    #788 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un profil jetable de reverse proxy TLS en boucle locale qui vérifie l'isolation#787

    des artefacts authentifiés…

    Ajoute un profil jetable de reverse proxy TLS en boucle locale (loopback) qui vérifie l'isolation des artefacts authentifiés, la sauvegarde et la restauration, l'expiration, et le retour arrière atomique lors d'une mise à niveau, sans déployer de service.

    #787 (ticket sur GitHub)
  • ModifiéFonctionneDocumenter les tâches CLI SSH ponctuelles, les enregistrements d'artefacts et#787

    d'incidents, la récupération synthétique…

    Documente les tâches CLI SSH ponctuelles, les enregistrements d'artefacts et d'incidents, la récupération synthétique, ainsi que la frontière distincte et future du service (santé, proxy, TLS et pare-feu).

    #787 (ticket sur GitHub)
  • AjoutéFonctionneAjouter le profil opérateur du service distant auto-hébergé pour les liaisons privées,#787

    les preuves de santé authentifiées…

    Ajoute le profil opérateur du service distant auto-hébergé : liaisons privées, preuves de santé authentifiées, références de secrets par fichier, enregistrements d'incidents, restauration cohérente avec SQLite, retour arrière de version et expiration explicite des artefacts terminaux.

    #787 (ticket sur GitHub)
  • AjoutéFonctionneAjouter une politique de cible distante liée au projet pour les futures tâches en file#786

    d'attente.

    Lorsqu'un worker la lie, elle valide les cibles et les paramètres, revérifie le DNS au moment de la distribution, épingle les requêtes HTTP et les requêtes de ressources navigateur, et applique des budgets de requêtes par origine et au total. Les proxys distants et les backends navigateur alternatifs échouent en mode fermé tant que leur sortie réseau n'est pas prouvée sûre.

    #786 (ticket sur GitHub)
  • AjoutéFonctionneAjouter une file SQLite isolée par projet et un worker de scan natif avec bail pour l'API#785

    distante optionnelle…

    Ajoute une file SQLite isolée par projet et un worker de scan natif avec bail, pour l'API distante authentifiée et optionnelle. Les tâches conservent les scans natifs et les rapports JSON/Markdown, prennent en charge la soumission idempotente, l'annulation, la reprise après échec au redémarrage, les téléchargements d'artefacts limités au périmètre et une rétention explicite, sans activer d'écouteur par défaut.

    #785 (ticket sur GitHub)
  • ModifiéFonctionneDéfinir un contrat optionnel, authentifié et versionné d'API de scan distant, avec des#784

    paramètres de crawl natifs bornés…

    Définit un contrat optionnel, authentifié et versionné d'API de scan distant, avec des paramètres de crawl natif bornés, des permissions limitées au projet, une soumission idempotente, un schéma OpenAPI et des preuves compatibles avec le statut de scan. Il exige des workers durables et séparés, ainsi qu'une politique de cibles et de sortie réseau ; les installations locales CLI/MCP ne changent pas (#784).

    #784 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un runbook SSH Ubuntu épinglé et un test de cycle de vie Linux jetable qui prouve#783

    l'installation…

    Ajoute un runbook SSH Ubuntu épinglé et un test de cycle de vie Linux jetable, qui prouve l'installation, le rendu JavaScript, la découverte des artefacts, la mise à niveau, les preuves de version et le retour arrière, sans service distant.

    #783 (ticket sur GitHub)
  • ModifiéFonctionneNormaliser les données analytiques et de recherche importées pour les jointures de scan#781

    (#781).

    evidence-normalize lit intégralement hors ligne un export CSV/XLSX/JSON fourni ou une enveloppe seohead.provider-evidence.v1 enregistrée, et produit un document seohead.normalized-evidence.v1 versionné à partir d'un manifeste seohead.evidence-mapping.v1 facultatif. Il conserve la provenance par champ (enveloppe, déclarée ou inconnue) pour la source, l'identité du rapport, la période, le fuseau horaire, l'attribution, le moteur, la couverture de collecte et le lien aux URL. Une mesure 0 reste zéro, tandis que les lignes manquantes, les cellules nulles ou vides, les cellules de formule, les valeurs supprimées, les périodes non collectées et une collecte échouée ou ignorée restent explicitement indisponibles. evidence-join joint les données normalisées à une liste de scan, d'audit ou de pages selon la politique de clé stricte external_join.v1, avec des assouplissements explicites uniquement. Il conserve les populations appariées, présentes seulement dans le crawl, présentes seulement en externe et non clés, au grain déclaré, et signale les collisions de clés au lieu de multiplier les lignes. --compare avec une politique déclarée ajoute une décision pure compatible, incompatible ou inconnue sur la période, la frontière de fuseau horaire, l'identité, l'attribution, le moteur et le grain, et signale l'éligibilité des quadrants à zéro mesuré pour les travaux de cohorte en aval. Les sources restreintes conservent leurs lignes et identifiants dans un artefact local privé et ne renvoient que des comptes.

    #781 (ticket sur GitHub)
  • AjoutéFonctionneAjouter une expérience hors ligne de disponibilité des fournisseurs, avec des références#780

    d'identifiants masquées…

    Ajoute une expérience hors ligne de disponibilité des fournisseurs, avec des références d'identifiants masquées, des schémas de routes d'opération, des métadonnées de quota et de confidentialité, et des états d'accès à la cible explicites. La seule présence d'un identifiant ne vérifie jamais une autorisation.

    #780 (ticket sur GitHub)
  • ModifiéFonctionneÉtendre seohead watch en observateur de projet en lecture seule, avec navigation dans#775

    les constats conservés…

    Étend seohead watch en observateur de projet en lecture seule, avec navigation dans les constats conservés, détail des preuves, état des vues enregistrées et de la revue, et notifications de boîte de réception MCP explicitement limitées à un périmètre.

    #775 (ticket sur GitHub)
  • AjoutéFonctionneAjouter la livraison autorisée de rapports synthétiques, avec des reçus d'idempotence#773

    durables…

    Ajoute la livraison autorisée de rapports synthétiques, avec des reçus d'idempotence durables et un comportement sûr en cas de nouvelle tentative après redémarrage.

    #773 (ticket sur GitHub)
  • ModifiéFonctionneConserver les revendications de livraison incertaines après une sortie de processus ou#773

    une confirmation malformée…

    Conserve les revendications de livraison incertaines après une sortie du processus ou une confirmation de document malformée, en empêchant un second envoi automatique lorsque l'acceptation ne peut pas être établie.

    #773 (ticket sur GitHub)
  • ModifiéFonctionneMesurer les aperçus de rapports à partir des preuves conservées, y compris la taille#772

    rendue et le digest source…

    Mesure les aperçus de rapports à partir des preuves conservées, y compris la taille rendue, le digest source, les effectifs de population, la couverture et le profil ; signale les moteurs de rendu manquants et les entrées trop volumineuses avant envoi. Aligne le budget JS du wizard approfondi sur le contrat de file partagé.

    #772 (ticket sur GitHub)
  • ModifiéFonctionneConserver les identités exactes de distribution confirmées du bot malgré les plantages de#771

    file et de propriété…

    Conserve les identités exactes des distributions de bot confirmées, malgré les plantages de file et de propriété, déduplique les mises à jour de confiance et isole le statut, l'annulation, la reprise et la livraison par acteur et chat à l'origine. Des relances volontaires identiques restent des tâches distinctes.

    #771 (ticket sur GitHub)
  • CorrigéFonctionneRestaurer la dernière tâche confirmée de l'acteur et du chat après le redémarrage du#771

    service…

    Restaure la dernière tâche confirmée de l'acteur et du chat après le redémarrage du service, en préservant le comportement d'annulation et de relance reconfirmée, sans reprendre un brouillon non confirmé.

    #771 (ticket sur GitHub)
  • AjoutéFonctionneAjouter le paquet de preuves de revue logicielle pour l'auto-hébergement, le juridique et#761

    les achats…

    Ajoute le paquet de preuves de revue logicielle pour l'auto-hébergement, la revue juridique et les achats (#761). scripts/generate_review_pack.py génère et vérifie un inventaire versionné des dépendances et licences (un profil par groupe d'installation, avec versions résolues et sources de licence mesurées dans l'environnement de génération ; les exigences exclues par marqueur, non satisfaites par la spécification ou non installées sont consignées et non supprimées). Il produit aussi un document de provenance au niveau de la version, qui relie les distributions construites à un tag et à la révision source du manifeste de build embarqué, ainsi qu'un SHA256SUMS.txt couvrant l'ensemble. La génération refuse un tag qui ne correspond pas à pyproject.toml. La vérification revalide les formats et les hash enregistrés, réextrait chaque distribution pour revalider son manifeste embarqué, le nom et la version déclarés par son nom de fichier, ainsi que les champs Name et Version de son propre *.dist-info/METADATA ou PKG-INFO par rapport à pyproject.toml, sans faire confiance à l'enregistrement. Un marqueur sentinelle SEOHEAD_REVIEW_CANARY_* prouve que les fichiers du paquet et les diagnostics ne contiennent aucun identifiant ou marqueur client glissé. La CI régénère et vérifie le paquet avec un tag jetable à chaque exécution ; le workflow de release le vérifie et l'attache à une vraie release v*.

    #761 (ticket sur GitHub)
  • AjoutéFonctionneAjouter docs/SOFTWARE_REVIEW.md : la carte des points d'accès sortants et des flux de#761

    données…

    Ajoute docs/SOFTWARE_REVIEW.md : la carte des points d'accès sortants et des flux de données (ce que chaque fonction contacte et envoie, et si l'appel est optionnel), la frontière locale et distante, le stockage des identifiants et des artefacts, l'état de la télémétrie, le signalement de sécurité et l'état de maintenance, ainsi que la manière de relire les changements de release. Il renvoie vers les runbooks d'installation et de déploiement (#783, #787) au lieu de les dupliquer.

    #761 (ticket sur GitHub)
  • AjoutéFonctionneAjouter une vérification préalable hors ligne de capacité et de somme de contrôle pour#760

    Google Sheets…

    Ajoute une vérification préalable hors ligne de capacité et de somme de contrôle pour Google Sheets, destinée aux paquets BI locaux complets ; elle n'effectue aucune requête Google ni aucune écriture dans le tableur.

    #760 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un transport explicite de remplacement Google Sheets, à liste blanche, avec des#760

    mappings de feuilles par jeu de données…

    Ajoute un transport explicite de remplacement Google Sheets, limité par liste blanche, avec des correspondances de feuilles par jeu de données, une préparation et une relecture bornées, et une publication atomique unique de valeurs seules qui conserve les identifiants de feuilles existants.

    #760 (ticket sur GitHub)
  • ModifiéFonctionneJournaliser la préparation Google Sheets avant toute création d'étape distante et#760

    réconcilier une réponse perdue…

    Journalise la préparation Google Sheets avant toute création d'étape distante, et réconcilie une réponse de début perdue à partir des identifiants déterministes des feuilles de préparation avant toute nouvelle tentative.

    #760 (ticket sur GitHub)
  • ModifiéFonctionnePréserver les valeurs numériques et booléennes typées et les relectures Google#760

    clairsemées, rejeter les cibles en double…

    Préserve les valeurs numériques et booléennes typées ainsi que les relectures Google clairsemées, rejette les cibles de feuilles en double et la dérive de contrat de jeu de données, lie la reprise à la cible configurée exacte et conserve la préparation reprenable après épuisement du quota. Budgète la croissance de la grille cible avant le remplacement atomique et signale les nombres de lignes non confirmés lors des exécutions interrompues.

    #760 (ticket sur GitHub)
  • ModifiéFonctionneValider les compagnons de groupe complets et liés à la source avant toute écriture de#760

    destination…

    Valide les compagnons de groupe complets et liés à la source avant toute écriture dans la destination, les conserve avec les constats sélectionnés, et signale les références d'appartenance purement locales dans les reçus de destination et de classeur, sans prétendre que le compagnon a été envoyé.

    #760 (ticket sur GitHub)
  • ModifiéFonctionneRépartir les grands ensembles d'enregistrements XLSX de scan-export en feuilles#759

    numérotées déterministes…

    Répartit les grands ensembles d'enregistrements XLSX de scan-export en feuilles numérotées et déterministes, avec une feuille Partitions qui conserve le nombre de lignes, au lieu d'échouer à la limite de lignes par feuille d'Excel.

    #759 (ticket sur GitHub)
  • ModifiéFonctionneRépartir les feuilles Constats et Pages de report-build à la limite de lignes d'Excel…#759

    Répartit les feuilles Constats et Pages de report-build à la limite de lignes d'Excel et émet un .xlsx.index.json haché, avec les plages exactes d'enregistrements, la population source, ainsi que les références de sélection et de couverture. Le rapport précédent est conservé en cas d'échec d'écriture détecté, et les fichiers temporaires de streaming sont nettoyés en cas d'interruption.

    #759 (ticket sur GitHub)
  • ModifiéFonctionneRefuser les cellules XLSX de plus de 32 767 caractères avant que la bibliothèque ne les#759

    tronque…

    Refuse les cellules XLSX de plus de 32 767 caractères avant que la bibliothèque ne les tronque, protège les métadonnées du résumé contre l'injection de formules et rejette les lignes d'audit conservées malformées avant qu'un export incomplet puisse se déclarer réussi. Les exports CSV et JSON complets ainsi que la politique bornée de vue d'ensemble PDF restent disponibles.

    #759 (ticket sur GitHub)
  • AjoutéFonctionneAjouter une livraison CSV BI sélectionnée et bornée, avec un comptage exact des lignes#759

    source, sélectionnées et omises…

    Ajoute une livraison CSV BI sélectionnée et bornée, avec un comptage exact des lignes source, sélectionnées et omises, la couverture source conservée, des hash calculés en flux et un index durable des plages CSV vers feuille XLSX. Les cellules Excel trop grandes échouent avant toute troncature, et une sortie interrompue n'est jamais marquée comme complète.

    #759 (ticket sur GitHub)
  • ModifiéFonctionnePréserver les lignes de couverture des contrôles, complètes et immuables, à côté des#759

    exports BI de constats…

    Préserve les lignes de couverture des contrôles, complètes et immuables, à côté des exports BI de constats sélectionnés, y compris les raisons des contrôles ignorés, et permet une sélection exacte des constats par segment de périmètre de crawl conservé.

    #759 (ticket sur GitHub)
  • AjoutéFonctionneAjouter des diagnostics de crawl hors ligne pour les scans natifs enregistrés et les#758

    anciens artefacts de run…

    Ajoute des diagnostics de crawl hors ligne pour les scans natifs enregistrés et les anciens artefacts de run, avec des preuves de décision bornées, des explications actionnables, un accès CLI/MCP en lecture seule et une commande et un outil d'export masqué distincts, activables sur option.

    #758 (ticket sur GitHub)
  • AjoutéFonctionneAjout de vues de constats de projet versionnées, avec filtres fermés et tri tenant compte#757

    de la gravité…

    Ajout de vues de constats de projet versionnées, avec filtres fermés, tri tenant compte de la gravité, projection de colonnes et pagination bornée. Le tri par gravité décroissante place les constats critiques en premier ; le tri croissant va de l'avis au critique. La CLI, le MCP, les rapports et la future navigation dans le terminal peuvent réutiliser la même vue en lecture seule, sans modifier les preuves sources, le scoring, les tâches ni la couverture.

    #757 (ticket sur GitHub)
  • AjoutéFonctionneAjouter une planification de surveillance locale désactivée par défaut, avec des budgets#756

    explicites…

    Ajoute une planification de surveillance locale, désactivée par défaut, avec des budgets explicites pour les rafraîchissements incrémentiels et complets, un refus de chevauchement, des revendications de reprise, une provenance d'observation immuable, la conservation des résultats partiels, des alertes dédupliquées et des notifications de rétablissement. Le moniteur ne démarre ni minuterie, ni crawl, ni canal de livraison.

    #756 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un adaptateur de livraison de service explicite et injecté pour les notifications#756

    complètes du moniteur.

    Exige une destination autorisée liée au projet et un magasin de reçus durable ; aucun transport, compte, minuterie ni destination n'est activé par défaut.

    #756 (ticket sur GitHub)
  • ModifiéFonctionneRendre les revendications de surveillance conservées, la couverture et la provenance du#756

    cache sûres au redémarrage…

    Rend sûrs au redémarrage les revendications de surveillance conservées, la couverture, la provenance du cache, les preuves de rétablissement dérivées et la livraison de service facultative.

    #756 (ticket sur GitHub)
  • AjoutéFonctionneAjouter un collecteur de moniteur ponctuel, explicite et borné par bail, avec des preuves#756

    conservées…

    Ajoute un collecteur de moniteur ponctuel, explicite et borné par bail, avec des preuves conservées tenant compte du cache et une livraison locale uniquement avec reçus.

    #756 (ticket sur GitHub)
  • AjoutéFonctionneAjout de verify-fixes / seo_verify_fixes pour revérifier des URL sélectionnées, dans#755

    des limites données…

    Ajout de verify-fixes / seo_verify_fixes : revérification bornée d’URL sélectionnées, à partir d’ID de constats enregistrés, d’une vue de vérification ou d’une liste d’URL explicite. La commande réutilise la politique de crawl enregistrée, écrit un artefact de vérification distinct sans écrasement ainsi qu’un rapport ciblé, et distingue les constats résolus, persistants, modifiés et non vérifiables. Un audit « after » existant ne peut être vérifié sans accès réseau que s’il possède un UUID de scan distinct et une date d’observation enregistrée plus récente. Une preuve non mesurée ou à l’échelle du site n’est jamais étiquetée comme corrigée.

    #755 (ticket sur GitHub)
  • ModifiéFonctionneLes crawls natifs d’URL peuvent filtrer les routes découvertes par extension de fichier#749

    avant…

    Les crawls natifs d’URL peuvent filtrer les routes découvertes selon l’extension finale du nom de fichier avant les requêtes, et selon le Content-Type réel de la réponse avant l’analyse ou la conservation du corps. Les deux étapes de filtrage journalisent leurs décisions tout en conservant les preuves de liens, de statuts, d’en-têtes et de redirections ; les métadonnées HTML filtrées restent explicitement non mesurées. Les ressources de script et de feuille de style conservent leur sélection indépendante et leurs propres budgets d’octets.

    #749 (ticket sur GitHub)
  • ModifiéFonctionneSi le corps HTML est indisponible, les constats dérivés conservent une couverture#749

    « ignorée » explicite…

    Si le corps HTML est indisponible, les constats dérivés du corps conservent désormais une couverture explicitement ignorée, au lieu de traiter les valeurs par défaut de l’analyseur comme propres ou comme métadonnées manquantes observées.

    #749 (ticket sur GitHub)
  • AjoutéFonctionneAjout d’exclusions auditables de motifs d’URL après analyse, pour les constats.#748

    Les constats supprimés restent dans le JSON d’audit et dans les exports de build de rapport, avec la règle correspondante et la raison. Les totaux des constats actifs, le score et le backlog de tâches reflètent la politique configurée. Les artefacts de scan natifs conservent cette politique pour une nouvelle analyse hors ligne ; le nombre de règles et la longueur des champs sont bornés.

    #748 (ticket sur GitHub)
  • AjoutéFonctionneAjout de scan-export (seo_scan_export) : un export hors ligne et en lecture seule des#747

    données de scan, sous le contrat versionné…

    Ajout de scan-export (seo_scan_export) : un export hors ligne et en lecture seule des données de scan, selon le contrat versionné scan_export.v1. La commande lit un artefact SQLite scan.v1 validé ou un audit.json de SF Analyzer, et écrit du CSV (un fichier par type d’enregistrement, plus un manifeste), du XLSX (classeur en écriture seule), une enveloppe JSON en flux, ou un document XML documenté. Chaque sortie contient la provenance, le nombre de lignes exportées, les statistiques d’exécution et une couverture explicite, y compris les contrôles exécutés, ignorés, désactivés ou restés non comptabilisés, que la sélection de champs ne peut pas supprimer. Les options --records et --fields assurent une projection validée sur les enregistrements de pages, de liens et de constats ; les types d’enregistrement ou les noms de champs inconnus sont rejetés avant la création du moindre fichier de sortie. Les valeurs absentes restent explicites (null en JSON, state="absent" en XML, \N en CSV/XLSX) au lieu de devenir des zéros fabriqués. La sortie XML est une sérialisation générée, avec un échappement UTF-8 correct ; elle n’analyse jamais de XML, de DTD, de feuilles de style ni d’entités fournis par l’appelant. Le CSV et le XLSX conservent la protection existante contre l’injection de formules ; le XLSX refuse les dépassements de lignes, de colonnes et de texte de cellule au lieu de tronquer, et toute erreur de sérialisation ne laisse aucun artefact partiel plausible.

    #747 (ticket sur GitHub)
  • ModifiéFonctionnecrawl-site gagne une vérification bornée et optionnelle des destinations externes#746

    enregistrées : discovery.external.crawl lance une phase distincte après la fermeture de la file de crawl interne, et récupère une fois chaque cible de lien sortant distincte, sous ses propres budgets external_checks.max_targets, max_hosts, max_requests, max_depth et max_redirects. Jamais de parcours récursif hors de l’hôte. Les résultats (récupéré, échoué, bloqué, ignoré avec la règle qui a refusé) sont ajoutés à external_checks.jsonl dans le répertoire de l’exécution, conservent la provenance de la page source, persistent après reprise sans rouvrir les budgets épuisés, et publient leur propre couverture dans discovery.external_checks, distincte de l’exhaustivité du crawl interne. Nécessite discovery.external.store ; refusé nommément sur la route SQLite native (--scan-out) tant que ce collecteur n’intègre pas la phase.

    #746 (ticket sur GitHub)
  • AjoutéFonctionneAjout d’une politique explicite et validée de proxy HTTP sortant pour le crawl natif, sur#745

    toutes les requêtes…

    Ajout d’une politique explicite et validée de proxy HTTP sortant pour le crawl natif, couvrant les requêtes de pages, de sitemaps, de ressources et du navigateur épinglé, avec une provenance de route masquée.

    #745 (ticket sur GitHub)
  • ModifiéFonctionneL’étape de rendu du crawler natif expose désormais son navigateur par la configuration,#744

    au lieu de figer Chromium : rendering.browser.engine choisit chromium (toujours par défaut), firefox ou webkit, via le même chemin Playwright protégé. Un nom inconnu échoue à la validation des réglages, et non au lancement. Un moteur demandé dont le binaire n’est pas installé renvoie une erreur de dépendance qui indique la correction (playwright install <engine>), au lieu de revenir silencieusement à Chromium. La limite documentée de Firefox est appliquée honnêtement : il rejette rendering.browser.mobile_emulation (is_mobile n’y est pas pris en charge), tandis que rendering.browser.touch_emulation (has_touch), indépendant, atteint toujours le contexte. Les sondes et les rendus complets partagent une même configuration effective : un motif n’est donc jamais escaladé par un navigateur différent de celui qui a produit ses preuves.

    #744 (ticket sur GitHub)
  • ModifiéFonctionnerendering.browser.viewport_width et rendering.browser.viewport_height ajoutent des#744

    dimensions de viewport libres aux préréglages existants desktop et mobile, qui continuent de définir le profil comme avant. La paire est tout ou rien et bornée à 1..16384 px. Un couple personnalisé remplace uniquement les dimensions du préréglage – il n’active ni l’émulation mobile ni l’émulation tactile, qui restent des indicateurs explicites que l’opérateur doit déclarer.

    #744 (ticket sur GitHub)
  • ModifiéFonctionnerendering.browser.page_concurrency borne le nombre de récupérations navigateur en cours#744

    pendant l’escalade…

    rendering.browser.page_concurrency borne le nombre de récupérations navigateur simultanées pendant l’escalade, indépendamment de speed.concurrency, qui continue de gérer la politesse du crawl HTTP. La valeur par défaut, 1, conserve le comportement séquentiel et ne crée aucun pool. Au-delà de 1, les sondes et les rendus tournent sur un pool de workers borné, tandis que chaque verdict, chaque validation et chaque écriture SQLite restent sur le thread orchestrateur, dans l’ordre de soumission. Le délai de rendu, le budget d’URL et les politiques par échantillon ou complètes tiennent sous concurrence ; un lot arrêté attend les pages déjà démarrées et n’en planifie aucune nouvelle ; les workers interrompus ou en échec ne laissent aucun thread, page, contexte ni navigateur actif derrière l’appel.

    #744 (ticket sur GitHub)
  • ModifiéFonctionneLe moteur choisi, sa version réellement rapportée, le viewport effectif et la concurrence#744

    de pages configurée sont enregistrés dans le manifeste et l’empreinte du crawl, ainsi que dans la provenance de rendu de chaque document rendu, y compris les tentatives échouées, qui consignent ce qui a été demandé sans inventer de rendu réussi. Les deux chemins d’escalade respectent ces réglages : le crawl de répertoire et le scan SQLite natif, où les candidats de liens rendus entrent dans la file via l’admission dédupliquée existante, une fois rendering.rendered_links.crawl activé.

    #744 (ticket sur GitHub)
  • AjoutéFonctionneAjout de contrôles optionnels de politique canonical pour les motifs d’URL de pagination#727

    et de filtres configurés, dans les pipelines d’audit de l’export SF et du crawl natif. Les règles de pagination acceptent comme cible la page elle-même, la première page ou une page d’atterrissage ; les règles de filtres acceptent la page elle-même ou une page d’atterrissage. Les politiques absentes et les cibles absentes des preuves de crawl restent non mesurées, et les contrôles de statut de réponse des destinations restent distincts.

    #727 (ticket sur GitHub)
  • AjoutéFonctionneAjout d’archives GSC Search Analytics reprenables dans l’historique local partagé des#718

    fournisseurs (SQLite)…

    Ajout d’archives reprenables des données Search Analytics de GSC dans le stockage SQLite local partagé de l’historique des fournisseurs, accessible de façon cohérente via gsc-archive et seo_gsc_archive. Le statut hors ligne, la préparation explicite, la collecte bornée et les instantanés vérifiés reposent sur un même noyau.

    #718 (ticket sur GitHub)
  • ModifiéFonctionneConservation de la provenance fournisseur/moteur et des métriques nullables, mise en file#718

    des seules plages de disponibilité non couvertes, et persistance des attentes de quota et des nouvelles tentatives transitoires bornées.

    #718 (ticket sur GitHub)
  • AjoutéFonctionneAjout d’un historique SQLite local et versionné pour GA4, Metrika, les requêtes et pages#716

    web GSC, et Yandex…

    Ajout d’un historique SQLite local et versionné, unique, pour les données quotidiennes de GA4, Metrika, des requêtes et pages web de GSC, et de Yandex Webmaster, avec remplacement atomique par journée et couverture explicite : demandée, vide, partielle, en échec ou en retard.

    #716 (ticket sur GitHub)
  • AjoutéFonctionneSynchronisation déterministe et bornée, statut hors ligne et export JSON/CSV via le CLI#716

    et le MCP local partagés…

    Synchronisation déterministe et bornée, statut hors ligne et export JSON/CSV exposés via le CLI et le MCP local partagés, avec l’additivité des métriques et des métadonnées de fuseau horaire prudentes. Aucun identifiant ni donnée de fournisseur n’est stocké dans le dépôt.

    #716 (ticket sur GitHub)
  • ModifiéFonctionneLe mode A de SF vérifie désormais les capacités d’export demandées par le CLI installé et#715

    exige un jeu complet et récent…

    Le mode A de SF vérifie désormais les capacités d’export demandées par le CLI installé et exige un jeu complet d’exports récents avant toute analyse. La provenance du profil complet enregistre le manifeste d’export vérifié et la relecture de la vitesse de crawl ; une limite de débit explicite échoue avant le crawl lorsque sa configuration de base est absente ou invalide.

    #715 (ticket sur GitHub)
  • ModifiéFonctionnemetrika-report (seo_metrika_report) et MetrikaClient.report() : un refus « Query is#714

    too complicated » de l’API Reporting est désormais relancé par tranches de mois civils, avec une attente de 5 à 15 s. Une tranche qui refuse encore est renvoyée avec un échantillonnage accuracy=0.1. Seules les métriques prouvées additives sur des périodes disjointes (ym:s:visits, ym:s:pageviews) sont fusionnées. Une requête portant sur des visiteurs uniques, des pourcentages, des moyennes ou des métriques non vérifiables est refusée avant la première requête de tranche, plutôt que de renvoyer une valeur sommée et fausse. Les tranches sont fusionnées au fil de leur arrivée sous un plafond global de lignes, qui borne aussi les téléchargements : une fois ce plafond atteint, les partitions restantes ne sont jamais demandées et leurs intervalles de dates sont nommés dans split.unfetched. Une tranche interrompue en cours de route y indique son propre intervalle avec partial. Les total_rows et totals de la période entière restent inconnus lorsque les périodes non interrogées les rendent impossibles à connaître, et la fenêtre renvoyée est marquée partielle. Les réponses fusionnées réappliquent le sort de l’appelant (dimensions et métriques, ou le tri par défaut de l’API : première métrique décroissante), et la fenêtre offset/limit est prise dans l’ensemble fusionné global. Les champs d’échantillonnage reflètent ce que l’API a réellement rapporté (sampled, pire sample_share) ; une tranche qui ne les renvoie pas laisse la valeur de la période entière inconnue, soit null dans la réponse CLI/MCP, jamais un false inventé. contains_sensitive_data est la disjonction (OU) des tranches, min/max sont recalculés sur les lignes fusionnées, et les cellules ou totaux de métriques absents ou mal formés marquent le corps incomplete au lieu d’être lus comme zéro. Le bloc split conserve les périodes demandées et résolues, le fuseau horaire utilisé, ainsi que la précision, les tentatives, les lignes écartées et les métadonnées d’échantillonnage de chaque tranche. Une partition en échec nomme les intervalles terminés et les précisions épuisées. Les dates relatives (today, NdaysAgo) se résolvent dans le timezone de la requête ou dans le fuseau du compteur (time_zone_name, sinon son décalage en minutes), jamais dans la date de l’hôte. Une période qui ne peut pas être convertie en dates (un raccourci comme month) est tout de même relancée et échantillonnée avant que l’erreur ne soit remontée. Un accuracy explicite est respecté sous toutes les formes documentées (low, medium, high, full, ou une part numérique comme "1") : tout ce qui dépasse l’échantillon de dernier recours conserve le repli accuracy=0.1, tandis qu’un réglage déjà plus bas (low ou une part égale ou inférieure) est préservé et n’est pas rééchantillonné à la hausse. Chaque requête tentée, y compris l’appel global refusé, est inscrite dans le journal des dépenses.

    #714 (ticket sur GitHub)
  • ModifiéFonctionneYandex Webmaster : l’opération indexing lit désormais le vrai endpoint v4 et non plus#713

    un chemin inexistant…

    Yandex Webmaster : l’opération indexing lit désormais le vrai endpoint v4 /indexing/samples au lieu de l’inexistant /search-urls. La nouvelle opération broken_links_samples lit /links/internal/broken/samples, et la pagination respecte la taille de page documentée de chaque endpoint (500 pour les requêtes, 100 pour les listes d’échantillons) au lieu d’envoyer limit=500 partout (#713).

    #713 (ticket sur GitHub)
  • ModifiéFonctionneLa collecte paginée de Yandex Webmaster valide désormais le count documenté de chaque#713

    page et la forme de sa liste, y compris un count inférieur au nombre de lignes renvoyées. Elle demande au plus le reliquat du budget de lignes à chaque page, afin qu’une coupure max_rows ne puisse jamais dépasser et produire un faux complete. Pour une page unique non paginée, elle expose returned et truncated sous forme de tranche bornée, signale partial dès qu’il reste des lignes non lues, et fait échouer les pages mal formées au lieu d’annoncer un résultat vide complet (#713).

    #713 (ticket sur GitHub)
  • ModifiéFonctionneLe render-check utilise désormais la confiance de la plateforme, plus une autorité de#709

    certification explicitement choisie…

    Le render-check utilise désormais la confiance de la plateforme, complétée par une autorité de certification (CA) explicitement choisie, rejoue les sous-requêtes POST épinglées et signale les échecs de vérification de certificat sans détail de transport.

    #709 (ticket sur GitHub)
  • ModifiéFonctionneReconnaissance de l’échec de vérification TLS du transport proxy épinglé, et vérification#709

    de la confiance explicite envers une CA de fixture…

    Reconnaissance de l’échec de vérification TLS du transport proxy épinglé, et vérification, via un intercepteur CONNECT synthétique contrôlé par le projet, de la confiance explicite envers la CA de fixture, du rejeu POST, des plafonds de réponse et du rejet des cibles privées, sans modifier la confiance de la plateforme.

    #709 (ticket sur GitHub)

3 octobre 2026

5 ajouté8 modifié1 corrigé
  • AjoutéFonctionneAjout de crawl-import pour des bundles CSV de crawl tiers explicitement mappés, en#819

    conservant l’identité source…

    Ajout de crawl-import pour des bundles CSV de crawl tiers explicitement mappés. La commande conserve l’identité de la source étrangère, la couverture par champ, les observations en double et les données indisponibles dans third_party_crawl.v1, sans traiter le résultat comme un scan natif ni comme un audit SF.

    #819 (ticket sur GitHub)
  • AjoutéFonctionneAjout d’un transport Playwright distant optionnel vers le navigateur, avec vérification#808

    explicite de l’endpoint et de la version, états d’échec sûrs et aucun repli sur un lancement local, tout en conservant le rendu local par défaut.

    #808 (ticket sur GitHub)
  • AjoutéFonctionneAjout de requêtes Python en lecture seule, bornées et déterministes : chemin observé le#805

    plus court et recherche de liens entrants…

    Ajout de requêtes Python en lecture seule, bornées et déterministes, sur les liens des scans conservés : chemin observé le plus court et recherche de liens entrants. Chaque saut porte l’identité de l’enregistrement de scan, et la couverture d’un graphe partiel est explicite.

    #805 (ticket sur GitHub)
  • ModifiéFonctionneAligner la régression de routage des workflows fournisseur sur le contrat corrigé de#779

    requête de fréquence Wordstat d’Arsenkin (#720, #779).

    Alignement de la régression de routage des workflows fournisseur sur le contrat corrigé de la requête de fréquence Wordstat d’Arsenkin (#720, #779).

    #779 (ticket sur GitHub)
  • AjoutéFonctionneAjout de docs/PROVIDERS.md, une matrice générée des capacités fournisseurs et des#779

    workflows spécialisés (#779, épopée #753). Elle est produite à partir du registre des fournisseurs et d’un catalogue de workflows curé dans seohead/core/provider_matrix.py, via scripts/generate_provider_matrix.py. Pour chaque workflow, elle indique les commandes livrées, l’authentification, le coût et le quota, la classe de confidentialité, les limites, et le repli CSV via provider-join. Les statuts distinguent pris en charge, partiel, non pris en charge et non vérifié ; aucun fournisseur déclaré n’est étiqueté comme vérifié en conditions réelles, les travaux explicitement non pris en charge sont listés nommément, et une première version par phases est retenue sans prétendre couvrir tous les services. Les écarts entre le document versionné et les registres sont détectés par tests/test_docs_drift.py et tests/test_provider_matrix.py.

    #779 (ticket sur GitHub)
  • CorrigéFonctionneCorrection de keywords-exact / seo_keywords_exact, qui ne pouvait jamais renvoyer de#720

    résultat : la tâche visait un outil Arsenkin inexistant…

    Correction de keywords-exact / seo_keywords_exact, qui ne pouvait jamais renvoyer de résultat : la tâche était créée pour un outil Arsenkin nommé keywords_frequency, qui n’existe pas, si bien que chaque appel répondait 404 WRONG_TOOL. Le !W exact passe désormais par l’outil wordstat avec type=1, le tableau des expressions sous queries, et la région sous forme de liste à un seul élément.

    #720 (ticket sur GitHub)
  • ModifiéFonctionneDemander le sélecteur overal pour !W : les valeurs ws d’Arsenkin sont des#720

    opérateurs distincts…

    Demande du sélecteur overal pour !W : les valeurs ws d’Arsenkin sont des opérateurs distincts. base est large (WS), quoted est l’expression entre guillemets (« WS »), overal est la forme exacte d’un mot (!WS), que demande !W, et exact est la forme à ordre strict ([!WS]).

    #720 (ticket sur GitHub)
  • ModifiéFonctionneSupprimer avant envoi la ponctuation que le fournisseur refuse : une expression contenant#720

    / ou des guillemets…

    Suppression, avant envoi, de la ponctuation refusée par le fournisseur : une seule expression contenant / ou des guillemets faisait rejeter tout le lot avec 422 JSON_VALIDATION_ERROR. Les expressions réécrites sont renvoyées dans cleaned, pour que l’appelant voie celles qui ont été mesurées sous une autre forme.

    #720 (ticket sur GitHub)
  • ModifiéFonctionneRenvoyer frequencies sous la forme {phrase: {"base": N, "overal": N}} à côté de la#720

    charge brute du fournisseur…

    Renvoi de frequencies sous la forme {phrase: {"base": N, "overal": N}} à côté de la réponse brute du fournisseur. Une expression dont le résultat ne concerne que d’autres régions est omise et listée dans warnings, au lieu d’emprunter les chiffres d’une autre région.

    #720 (ticket sur GitHub)
  • AjoutéFonctionneAccès Topvisor en lecture seule et borné via le CLI partagé et le handler MCP, avec#719

    fichiers d’identifiants centralisés…

    Accès en lecture seule et borné à Topvisor via le CLI partagé et le handler MCP, avec fichiers d’identifiants centralisés, pagination explicite et aucune opération de contrôle payante.

    #719 (ticket sur GitHub)
  • ModifiéFonctionneAlignement du bloc historique sources.gsc de sources-doctor sur#717

    provider_status.gsc : ready et le nouveau champ components proviennent désormais des mêmes composants d’identifiants (jeton OAuth, autorisation durable ou compte de service), et non plus du seul fichier de jeton. Ainsi, un compte de service configuré n’apparaît plus comme « GSC is not set up ». Le composant compte de service valide désormais le document JSON lui-même (fichier régulier privé, taille bornée, type service_account, URI de jeton Google exacte et champs requis). Les deux blocs du doctor renvoient une énumération sûre service_account_status (missing, unsafe_file, too_large, unreadable, malformed_json, unsupported_shape ou configured_unverified). Un fichier trop volumineux, illisible ou mal formé reste ainsi distinct d’un fichier configuré mais non vérifié, sans exposer son contenu.

    #717 (ticket sur GitHub)
  • ModifiéFonctionneLes artefacts de scan de crawl-site portent désormais finished_at et un cycle de vie#712

    finished dès que chaque ligne de frontière acceptée atteint un état terminal, y compris pour les exécutions dont les preuves conservées sont partielles. crawl_partial nomme déjà les observations omises : une file vidée ne passe donc plus pour une capture interrompue dans scan-status, scan-list ou l’historique (#712). Une exécution arrêtée explicitement (interrompue avant d’avoir accepté du travail, annulée, ou stoppée par le disjoncteur d’erreurs) conserve interrupted et la raison enregistrée, même après vidage de la file, y compris via resume_or_finalize : les chemins d’arrêt ne reçoivent donc jamais un horodatage de fin erroné.

    #712 (ticket sur GitHub)
  • ModifiéFonctionneduplicate-check --scan et boilerplate-report --scan lisent désormais un corpus#710

    conservé en flux au lieu d’échouer sur des sites de taille normale…

    duplicate-check --scan et boilerplate-report --scan lisent désormais un corpus conservé en flux, au lieu d’échouer sur des sites de taille normale. Le délai d’ouverture et de validation du scan est calculé selon la taille de l’artefact, et chaque lecture de document a son propre délai : un corpus de 1 500 pages ne se termine plus en interrupted. Le budget d’octets du corpus compte ce que l’analyseur conserve réellement, à savoir le Markdown extrait pour les doublons et une empreinte par page pour le contenu répété, et non la taille du HTML brut. Lorsqu’une borne du corpus est atteinte, la couverture est signalée comme partielle, avec les décomptes exacts préparés et éligibles ainsi que la borne qui a arrêté la lecture (#710).

    #710 (ticket sur GitHub)
  • ModifiéFonctionnereport() et by_time() de Metrika rejettent désormais offset < 1 avec une#707

    ValueError…

    report() et by_time() de Metrika rejettent désormais localement offset < 1 avec une ValueError, au lieu de le transmettre à l’API Reporting, qui répondait offset=0 par HTTP 400. De nouveaux tests hors ligne fixent le contrat à partir de 1 pour metrika-report, seo_metrika_report et aggregate_report de provider-collect, et vérifient que les conditions d’arrêt paginées (total_rows, ROW_CAP) comptent les lignes sautées avant un offset non par défaut (#707).

    #707 (ticket sur GitHub)

2 octobre 2026

1 ajouté2 modifié
  • ModifiéFonctionnemetrika-traffic-pdf sous macOS : Chrome écrit le PDF et continue de tourner ; le#731

    navigateur est…

    metrika-traffic-pdf sous macOS : Chrome écrit le PDF et reste actif ; le navigateur est désormais lancé sans attendre, puis arrêté une fois le PDF vérifié.

    #731 (ticket sur GitHub)
  • ModifiéFonctionneYandex Webmaster : user_id est résolu à partir du jeton ; nouvelles opérations en#713

    lecture seule…

    Yandex Webmaster : user_id est résolu à partir du jeton. Nouvelles opérations en lecture seule : summary, diagnostics, sqi_history, search_history, query_history, in_search_history, events_history, indexing_history, important_urls, broken_links_history, external_links_history. Ajout de params pour les dates et les indicateurs, et pagination des listes de requêtes et d’échantillons de crawl (#713).

    #713 (ticket sur GitHub)
  • AjoutéFonctionneNouveau skill technique traffic-report : un rapport mensuel ou annuel destiné au

    client, à partir de Metrika, Webmaster et Search Console (conversions comptées comme visites, contrôles de cohérence des objectifs, produits, portrait des acheteurs, règles de mise en page des diapositives).

1 octobre 2026

1 ajouté1 modifié
  • AjoutéFonctionneAjout de metrika-traffic-pdf (seo_metrika_traffic_pdf) : un rapport de trafic#731

    statique au format A4 paysage, dans la mise en page d’un tableau de bord analytique, construit à partir de Yandex Metrika. La collecte et le rendu sont deux étapes séparées. La collecte lit l’API Reporting (environ 40 requêtes gratuites, en lecture seule) et produit un seul document seohead.metrika-traffic/1 : neuf cartes d’indicateurs (utilisateurs, visites, pages vues, pages par visite, visites par jour, taux de rebond, durée moyenne de visite, part des visiteurs avec deux ou trois visites, part des nouveaux visiteurs), avec leurs variations par rapport à la période précédente de même durée et aux mêmes dates un an plus tôt ; la dynamique quotidienne ; des fenêtres de 3, 6 et 12 mois comparées aux fenêtres qui les précèdent ; les moteurs de recherche, villes, pays, appareils, âge, sexe, principales pages d’atterrissage et expressions de recherche ; et tous les canaux de trafic. Le rendu met ce document en HTML autonome avec des graphiques SVG intégrés, puis l’imprime en PDF via Chrome, Edge ou Chromium installé localement (SEOHEAD_CHROME remplace la détection). L’identité visuelle (nom, couleurs, pile de polices, texte du logo) et les libellés en anglais ou en russe sont des entrées ; les lignes de requêtes Search Console peuvent être ajoutées comme page facultative. L’attribution par défaut est la dernière source significative (ym:s:lastSignTrafficSource et ses dimensions de moteur et d’expression), que reflète l’interface de Metrika ; les dimensions au dernier clic s’en écartent de quelques pour cent et restent un choix explicite attribution=last_click. Chaque requête passe offset=1, car l’API compte les lignes à partir de 1. Les données manquantes restent visibles : chaque bloc porte ok, unavailable ou skipped avec une raison ; une variation sans base de comparaison vaut null et non zéro ; l’absence de navigateur laisse le HTML en place et signale le PDF comme ignoré ; les fichiers existants dans out_dir ne sont remplacés qu’avec overwrite=true.

    #731 (ticket sur GitHub)
  • ModifiéFonctionneLes rapports Metrika commencent à offset=1 : l’API Reporting est en base 1 et répondait#707

    à chaque requête…

    Les rapports Metrika commencent à offset=1 : l’API Reporting compte à partir de 1, et répondait HTTP 400 à chaque requête envoyée avec offset=0 (#707, #728, #729).

    #707 (ticket sur GitHub)

26 septembre 2026

1 ajouté
  • AjoutéFonctionneAjout de la preuve native HEADING_SKIP pour les sauts de niveau H1–H6 dans la région de#725

    contenu nommée. Les titres de l’en-tête, du pied de page, de la navigation, de la barre latérale et ceux qui sont explicitement masqués ou situés dans des dialogues fermés sont exclus, afin qu’une interface de gabarit ne crée pas une fausse hiérarchie. Les exécutions en export seul de Screaming Frog signalent ce contrôle comme indisponible.

    #725 (ticket sur GitHub)

23 septembre 2026

1 modifié
  • ModifiéFonctionneAccepter les fichiers de secrets privés sous Windows, où les bits de permission POSIX#708

    n’existent pas, et ajouter un script de consentement…

    Acceptation des fichiers de secrets privés sous Windows, où les bits de permission POSIX n’existent pas, et ajout d’un script de consentement dans le navigateur qui enregistre une autorisation Search Console en lecture seule.

    #708 (ticket sur GitHub)

13 septembre 2026

2 ajouté3 modifié2 corrigé
  • AjoutéFonctionnePrise en charge, sous Windows, des modules d’écriture SQLite natifs, de l’historique, des#705

    nouvelles tentatives, des instantanés, des nouvelles analyses et de la publication de projets, avec des verrous par plage d’octets fournis par le système et des contrôles d’espace libre portables. Le vidage POSIX des répertoires est conservé ; le vidage des fichiers sous Windows et la publication atomique restent disponibles, sans garantie de fsync de répertoire POSIX. Les workflows portables sont testés dans la CI Windows et dans un environnement Linux isolé.

    #705 (ticket sur GitHub)
  • CorrigéFonctionneLe scan HTML en texte brut reste compatible avec les anciennes versions de Python, sans#705

    l’option de script récente de HTMLParser…

    Le scan HTML en texte brut reste compatible avec les versions de Python qui n’ont pas l’option de script récente de HTMLParser, y compris la distribution Windows de Python 3.12.

    #705 (ticket sur GitHub)
  • CorrigéFonctionneCorriger et sourcer les recommandations Google sur les données structurées et Googlebot,#704

    y compris la disponibilité FAQ/HowTo…

    Correction et sourcing des recommandations Google sur les données structurées et Googlebot, y compris la disponibilité FAQ/HowTo et les conséquences de la politique sur les données structurées.

    #704 (ticket sur GitHub)
  • ModifiéFonctionneDécouvrir les sitemaps depuis la racine du site via robots.txt, avec repli sur#703

    /sitemap.xml…

    Découverte des sitemaps à partir de la racine du site via robots.txt, avec repli sur /sitemap.xml. Lorsque l’expansion de tous les sitemaps échoue, le résultat est signalé ok: false.

    #703 (ticket sur GitHub)
  • ModifiéFonctionneAutoriser la reprise d’un crawl natif après des cookies anonymes posés par le serveur, et#702

    enregistrer la nouvelle session…

    La reprise d’un crawl natif est désormais possible après des cookies anonymes posés par le serveur, et la nouvelle session est enregistrée sans conserver les valeurs des cookies. Les crawls authentifiés et ceux à profil persistant restent non reprenables.

    #702 (ticket sur GitHub)
  • ModifiéFonctionneStandardisation : les chemins de scan enregistrés deviennent --scan, le JSON inline#701

    devient --input ; les anciennes…

    Standardisation : les chemins de scan enregistrés s’écrivent désormais --scan, et le JSON inline --input. Les anciennes formes, --input avec un chemin de scan et --json-input, continuent de fonctionner pendant une version, avec un avertissement.

    #701 (ticket sur GitHub)
  • AjoutéFonctionneAjout d’un consentement explicite, désactivé par défaut, pour conserver des preuves#700

    anonymes bornées portant Cache-Control: no-store. Les corps de réponses authentifiées continuent d’être omis.

    #700 (ticket sur GitHub)

9 septembre 2026

10 ajouté9 modifié2 corrigé
  • AjoutéFonctionneAjout d’aperçus hors ligne des priorités de projet et d’application explicite et#694

    versionnée de la politique, à partir des faits de stack enregistrés. Les choix de l’opérateur sont préservés, l’historique des politiques est atomique, et les explications de priorité correspondantes figurent dans les rapports lisibles.

    #694 (ticket sur GitHub)
  • CorrigéFonctionneCorriger les recommandations sur le rendu JavaScript, le canonical, l’hygiène des URL et#692

    notranslate, sans modifier les contrôles ni les sévérités…

    Correction des recommandations sur le rendu JavaScript, le canonical, l’hygiène des URL et notranslate, sans modifier les contrôles à l’exécution ni les niveaux de sévérité.

    #692 (ticket sur GitHub)
  • CorrigéFonctionneGarder les URL du sitemap et du robots.txt de la fixture de documentation sur l’origine#690

    loopback éphémère.

    #690 (ticket sur GitHub)
  • AjoutéFonctionneCouverture portable des checklists de projet, avec un catalogue dérivé des sources et#686

    packagé, des modèles personnalisés réutilisables…

    Couverture portable des checklists de projet : catalogue dérivé des sources et fourni avec le paquet, modèles personnalisés réutilisables, historique des définitions et des preuves, écritures concurrentes optimistes, revue manuelle explicite et revue des livrables, et vues hors ligne des éléments en attente, obsolètes ou bloqués, partagées entre le CLI, le MCP et les rapports humains liés au projet.

    #686 (ticket sur GitHub)
  • AjoutéFonctionneAjout d’un résumé de statut de scan natif en lecture seule pour les populations de la#685

    frontière et les résultats HTTP enregistrés.

    Ajout d’un résumé de statut de scan natif, en lecture seule, pour les populations de la frontière et les résultats HTTP enregistrés.

    #685 (ticket sur GitHub)
  • AjoutéFonctionneAjout d’espaces de travail de projet locaux et portables, avec des états explicites pour#678

    les checklists en attente et la préparation.

    #678 (ticket sur GitHub)
  • AjoutéFonctionneConsigner dans le dépôt la revue du guide Google Search Central : 175 guides lus, leurs#677

    étiquettes, leurs exclusions, la date de l’instantané et les trois correctifs produits…

    Consignation dans le dépôt de la revue du guide Google Search Central : 175 guides lus, leurs étiquettes, leurs exclusions, la date de l’instantané et les trois corrections qui en ont découlé.

    #677 (ticket sur GitHub)
  • ModifiéFonctionneMode URL de crawl-site : écriture par défaut d’un scan SQLite natif sans collision sous#676

    le dossier de l’appelant…

    Le crawl-site en mode URL écrit désormais, par défaut, un scan SQLite natif sans collision dans le dossier scans/ de l’appelant. --out-dir reste la voie explicite héritée vers un répertoire ; les entrées en liste ainsi que les configurations de cache en mode live ou replay désignent cette voie, au lieu de changer silencieusement de mode de collecte.

    #676 (ticket sur GitHub)
  • ModifiéFonctionneLes builds de distribution propres intègrent désormais une provenance de producteur#675

    validée pour les scans SQLite natifs, lorsqu’aucune copie de source n’est disponible.

    #675 (ticket sur GitHub)
  • ModifiéFonctionneRemplacer, dans le skill d’audit packagé, les affirmations non étayées sur la perte de#671

    signal des 301 et l’absence de transmission des 302…

    Dans le skill d’audit packagé, les affirmations non étayées sur la perte de signal fixe des 301 et l’absence totale de transmission de popularité des 302 sont remplacées par une logique d’intention permanente ou temporaire et de cible canonique, avec renvoi à Google Search Central. Les redirections temporaires restent valides pour les changements temporaires ; un code de statut seul ne mesure pas une perte de positionnement.

    #671 (ticket sur GitHub)
  • ModifiéFonctionnerender-check --viewport mobile utilise désormais une identité de diagnostic smartphone#670

    stable pour ses requêtes brutes et ses requêtes navigateur. Un --user-agent explicite est disponible via la CLI et le MCP, et chaque comparaison terminée ou partielle enregistre l’identité effective et la taille du viewport.

    #670 (ticket sur GitHub)
  • AjoutéFonctionneAjout d’entrées --scan en lecture seule pour l’analyse des doublons et du boilerplate#669

    sur un corpus, avec couverture du corps conservé et provenance.

    #669 (ticket sur GitHub)
  • AjoutéFonctionneCatalogue généré des entrées de commande ajouté, et documentation du stockage du scan, du#668

    cache HTTP et du journal d’exécution…

    Catalogue généré des entrées de commande ajouté, et documentation de la décision concernant le stockage du scan, du cache HTTP et du journal d’exécution.

    #668 (ticket sur GitHub)
  • ModifiéFonctionneLes rapports destinés au client (Markdown, CSV, XLSX, DOCX et tâches) utilisent désormais#660

    des intitulés de constats lisibles…

    Les rapports destinés au client (Markdown, CSV, XLSX, DOCX et tâches) utilisent désormais des intitulés de constats compréhensibles par le lecteur et les preuves de reproduction enregistrées, au lieu des identifiants du registre ou des noms de collecteurs. Les anciens enregistrements sans preuves suffisantes l’indiquent explicitement, tandis que les artefacts JSON d’audit restent inchangés.

    #660 (ticket sur GitHub)
  • AjoutéFonctionneAjout de project-facts pour enregistrer les faits de stack d’un projet après sa#648

    création, éventuellement à partir d’une passe…

    Ajout de project-facts pour enregistrer les faits de stack d’un projet après sa création, éventuellement à partir d’une seule passe explicite tech-detect respectueuse de robots.txt. Les décisions saisies par l’opérateur restent prioritaires sur les indices détectés ; une détection indisponible ou ambiguë reste absente, avec sa raison.

    #648 (ticket sur GitHub)
  • ModifiéFonctionneLe README commence par le contrôleur de projet, et Screaming Frog est présenté comme une#648

    seconde passe de vérification croisée, et non comme une norme de parité.

    #648 (ticket sur GitHub)
  • AjoutéFonctionneLivraison de examples/project-skeleton avec une checklist initialisée et vierge, pour#648

    que project…

    Livraison de examples/project-skeleton avec une checklist initialisée et vierge : project status affiche désormais des compteurs de couverture au lieu de not_initialized, et ce fichier est vérifié par rapport au catalogue en vigueur.

    #648 (ticket sur GitHub)
  • AjoutéFonctionneAjout des contrats de préparation de projet, de preuves fournisseur, de corpus#354

    sauvegardé, d’extraction bornée, de preuves de scan et de workflows/catalogue, avec des limites explicites sur les preuves conservées et la progression.

    #354 (ticket sur GitHub)
  • ModifiéFonctionneLes profils MCP et les wrappers de progression qui préservent les métadonnées exigent le#354

    SDK MCP optionnel en version 1.29 ou plus récente.

    Les profils MCP et les wrappers de progression qui préservent les métadonnées exigent le SDK MCP optionnel en version 1.29 ou ultérieure.

    #354 (ticket sur GitHub)
  • ModifiéFonctionneREADME simplifié autour des workflows tâche → commande → artefact, suppression des

    visuels obsolètes et des compteurs marketing…

    README simplifié autour des workflows tâche → commande → artefact : suppression des visuels obsolètes et des compteurs marketing, et conservation des liens vers les références générées de l’interface en vigueur.

  • ModifiéFonctionneREADME enrichi de workflows concrets entrée → résultat, avec les appels CLI/MCP

    correspondants et des limites exactes concernant le corpus conservé, le navigateur et les fournisseurs.

8 septembre 2026

8 modifié2 corrigé
  • ModifiéFonctionneDocumentation de l’artefact SQLite réalignée sur le corps natif livré, l’historique et#666

    les contrats de réanalyse hors ligne…

    La documentation de l’artefact SQLite est réalignée sur le corps natif livré, l’historique et les contrats de réanalyse hors ligne (#666). Le tableau des champs collectés tardivement est désormais vérifié contre le mapping de l’importateur : une observation JSONL plus ancienne reste NULL en SQL au lieu de devenir une valeur propre fabriquée.

    #666 (ticket sur GitHub)
  • ModifiéFonctionneLes audits natifs signalent désormais meta keywords, canonical secondaire, version HTTP#659

    et amphtml comme ignorés lorsque leurs champs source n’ont pas été collectés…

    Les audits natifs signalent désormais les contrôles meta keywords, canonical secondaire, version HTTP et amphtml comme ignorés lorsque leurs champs source n’ont pas été collectés.

    #659 (ticket sur GitHub)
  • CorrigéFonctionneNe plus lire comme identifiant de l’opérateur un cookie posé par le site dans la voie de#656

    rendu JavaScript, et signaler quand un run écarte des DOM rendus (#656)…

    Ne plus lire comme identifiant de l’opérateur un cookie posé par le site dans la voie de rendu JavaScript, et signaler explicitement quand un run écarte des DOM rendus (#656). Un navigateur renvoie tout ce que le Set-Cookie du site lui a donné : dès qu’une page pose un cookie de session puis demande une sous-ressource de même origine (un script, une feuille de style, une image, la forme ordinaire du web), le hook de requête du rendu lisait l’en-tête Cookie: sur le réseau et enregistrait le DOM sérialisé de cette page comme omitted/credentialed, sur un run avec http.credential_headers = []. Chaque rendu crée son propre contexte navigateur, donc la perte est par page et non cumulative : chaque page qui pose un cookie perd son propre DOM, et le run rapporte ses pages, ses liens et ses compteurs d’escalade exactement comme s’il était complet. credentials_used pour un document rendu ne provient désormais que de ce que le run a été configuré pour envoyer (http.credential_headers ou un profil de navigateur persistant), ce que crawl/sqlite_render.py::_policy_facts dérive déjà et transmet au moteur de rendu ; celui-ci construit son propre client réseau sans identifiant propre, donc le réseau n’avait rien à ajouter. Un crawl avec un identifiant configuré continue d’omettre ces DOM sous credentialed, inchangé, et la valeur du cookie n’est toujours jamais stockée.

    #656 (ticket sur GitHub)
  • ModifiéFonctionneLes compteurs de rendu qu’un indicateur partial ne peut pas exprimer sont désormais#656

    nommés.

    rendered_bodies dans un résultat de crawl-site indique combien de DOM rendus ont été conservés et la raison de chaque DOM écarté ; la CLI l’affiche à côté de la ligne de fin, au lieu de laisser ce renseignement à un indicateur de capacité qui dit « partial » pour un seul DOM manquant comme pour tous. Un run qui n’a rien écarté n’affiche rien de plus. Les compteurs sont relus dans l’artefact de scan : un scan terminé répond donc encore à la même question après coup.

    #656 (ticket sur GitHub)
  • ModifiéFonctionneCollecte de og:url lors d’un crawl natif, au lieu de signaler chaque page comme n’en#654

    ayant pas (#654).

    rules.check_og liste og:url parmi les missing_tags d’une page dès que le champ est vide, mais le chemin natif ne lisait jamais cette balise : ni og_url dans PageRecord, ni colonne og_url dans scan_v1.sql, ni OG:URL dans la projection Internal:All que crawl/evidence.py construit. La colonne n’existait que côté Screaming Frog, où normalize résolvait toujours OG:URL ; un export du site voyait donc la vraie valeur, alors qu’un crawl natif du même site signalait un défaut. C’était un champ non mesuré présenté comme mesuré, sur chaque page de chaque crawl natif, quel que soit le balisage. La balise est désormais lue au même endroit que les trois autres (le parseur la renvoyait déjà sous og:url), stockée dans pages.og_url, colonne nullable comme toutes les colonnes ajoutées tardivement, de sorte qu’un enregistrement écrit avant sa collecte reste distinguable d’une page qui n’en déclare aucune, puis projetée en OG:URL. C’est le côté collecte du raccord dont #646 avait corrigé le côté lecture. tests/test_open_graph_seam.py gagne un troisième site de test dont les pages ont Open Graph sans og:title, pour que le constat se déclenche réellement et que sa liste soit lisible : une page déclare og:url et ne doit pas être citée comme en manquant, l’autre n’en déclare aucun et doit l’être. Le test déterminant audite ces deux pages deux fois, une fois depuis le crawl et une fois depuis un export Internal:All décrivant les mêmes pages, et exige le même verdict. #646 et #654 étaient toutes deux des situations où deux chemins étaient en désaccord, sans test qui les couvre ensemble.

    #654 (ticket sur GitHub)
  • CorrigéFonctionneNe plus lire comme identifiant un cookie posé par le site, et signaler quand un run#647

    écarte des corps de page (#647).

    Ne plus lire comme identifiant un cookie posé par le site, et signaler explicitement quand un run écarte des corps de page (#647). Un crawl partage un seul client HTTP, et ce client conserve un cookie jar : dès qu’une réponse portait Set-Cookie, chaque requête suivante partait avec Cookie:, et le writer du corpus la classait comme une récupération authentifiée. Sur un site public avec http.credential_headers = [] et credentials_acknowledged = false, cela a écarté 33 001 des 40 920 corps de page, et le run rapportait ses pages et ses liens comme s’il était complet. Tout ce qui se calcule à partir du HTML stocké sur ce crawl (détection des quasi-doublons, profondeur et nombre de nœuds du DOM, part du boilerplate, structure des titres dans le corps, réanalyse hors ligne) couvrait alors 7 903 pages, alors que chaque pourcentage au niveau page du même rapport portait sur 40 920 : deux populations présentées comme une seule. Une capture est dite authentifiée lorsque le run a été configuré pour envoyer un en-tête d’identifiant à cet hôte, seul moyen pour un en-tête sensible d’atteindre une requête construite par le crawler, puisque http.headers est refusé par la validation de configuration. Un crawl avec un identifiant configuré omet toujours ces corps sous credentialed, inchangé.

    #647 (ticket sur GitHub)
  • ModifiéFonctionneLes compteurs qu’un indicateur partial ne peut pas porter sont désormais nommés.#647

    html_bodies dans un résultat de crawl-site indique combien de corps HTML de pages récupérés ont été conservés, et la raison de chaque corps écarté ; la CLI l’affiche à côté de la ligne de fin, au lieu de laisser ce renseignement à un indicateur qui dit « partial » pour un seul corps manquant comme pour quatre cinquièmes d’entre eux. Un run qui n’a rien écarté n’affiche rien de plus. Les listes d’en-têtes de requête et de réponse expurgées conservent désormais les noms des en-têtes retirés par l’expurgation, sous x-seohead-redacted-headers, jamais leurs valeurs. Auparavant, deux réponses dont les corps avaient été traités différemment enregistraient des listes d’en-têtes identiques octet pour octet, si bien qu’un opérateur lisant l’artefact ne pouvait pas savoir pourquoi un corps manquait.

    #647 (ticket sur GitHub)
  • ModifiéFonctionneLes entrées du changelog sortent de CHANGELOG.md : un fichier par modification sous#638

    changelog.d/…

    Les entrées du changelog sortent de CHANGELOG.md pour devenir un fichier par modification sous changelog.d/, afin qu’une pull request n’entre plus en conflit avec toutes celles fusionnées avant elle (#638). Chaque branche ajoutait son entrée en tête de ## Unreleased, si bien que cette seule ligne était le point de contention du fichier : neuf résolutions manuelles réparties sur huit pull requests en deux sessions, chacune suivie d’un nouveau push et d’une nouvelle CI, avec toujours la même résolution, « garder notre bloc, puis le leur ». Un conflit dont la réponse ne varie jamais ne porte aucune information ; c’est seulement une occasion de perdre un paragraphe en pensant à autre chose. La correction de .gitattributes proposée dans l’issue, CHANGELOG.md merge=union, a été mesurée puis rejetée : union fusionne ligne à ligne, donc quand deux entrées contiennent une même ligne (une ligne vide dans une entrée suffit), elle en garde une copie et annonce un succès, en supprimant la ligne de l’autre entrée sans conflit et sans que personne soit invité à vérifier. Un premier test avec des lignes volontairement distinctes avait fusionné proprement et masqué le problème. Remplacer un conflit bruyant par une perte silencieuse de données est pire que le conflit ; la correction structurelle est donc celle qui a été livrée.

    #638 (ticket sur GitHub)
  • ModifiéFonctionneUn fragment est nommé d’après l’issue qu’il ferme (changelog.d/638.md), la clé propre à#638

    chaque branche…

    Un fragment est nommé d’après l’issue qu’il ferme (changelog.d/638.md), clé unique à chaque branche par construction : une pull request qui ferme deux issues écrit deux fragments, un par issue, et une modification qui n’en ferme aucune écrit no-issue-<slug>.md. Un fragment contient l’entrée exactement telle qu’elle doit figurer dans le changelog (une ou plusieurs puces de premier niveau avec leurs lignes de suite, sans front matter ni enveloppe), pour que les entrées en prose multi-paragraphes de ce fichier soient restituées octet pour octet, et non réduites à des lignes uniques. python scripts/build_changelog.py les intègre dans ## Unreleased au moment de la release, ordonnées par numéro d’issue et non selon l’ordre que rend le système de fichiers, et --prune supprime les fragments intégrés. L’assemblage remplace toute la zone comprise entre deux commentaires de marquage au lieu d’y insérer, donc l’exécuter deux fois produit le même fichier, que les fragments aient été supprimés entre-temps ou non. CHANGELOG.md lui-même n’est pas régénéré à chaque pull request, délibérément : une garde qui le maintiendrait constamment synchronisé remettrait les deux branches dans le même fichier et recréerait le conflit que cela supprime.

    #638 (ticket sur GitHub)
  • ModifiéFonctionneLes gates de documentation qui lisaient CHANGELOG.md étaient le risque : une garde qui#638

    cesse discrètement de contrôler…

    Les gates de documentation qui lisaient CHANGELOG.md étaient le risque, car une garde qui cesse discrètement de contrôler est pire que les conflits. Les deux ont été repérées et couvrent désormais les fragments. tests/test_docs_drift.py contenait CHANGELOG.md dans PUBLIC_MARKDOWN : la garde de langue anglaise seule, celle des « références aux seules commandes existantes » et celle de dérive des compteurs lisent donc aussi changelog.d/*.md, et les deux gates de dérive des compteurs ignorent un fragment pour la même raison qu’elles ignorent le changelog : une entrée enregistre ce qui était vrai au moment de son écriture. tests/test_doc_counts.py exclut délibérément le changelog de son analyse des compteurs en direct, et sa liste de fichiers n’atteint jamais changelog.d/, ce qui répond de la même façon pour la même raison ; tests/test_doc_commands.py, tests/test_docs_commands_execute.py et tests/test_examples_gate.py ne lisent jamais le changelog. Un nouveau tests/test_changelog_fragments.py fixe chacune de ces réponses, ainsi que la nomenclature des fragments, l’ordre déterministe, l’assemblage idempotent, et le fait que deux branches concurrentes simulées, ajoutant chacune un fragment, fusionnent sans conflit.

    #638 (ticket sur GitHub)

Antérieur (date non enregistrée)

23 ajouté30 modifié17 corrigé
  • CorrigéFonctionneContinuer d’identifier une page dont le site envoie un en-tête Set-Cookie sans valeur

    (#651).

    Un en-tête sans paire name=value, comme Set-Cookie: Secure; HttpOnly que emall.by envoie à côté de deux cookies bien formés, devient Cookie(name='Secure', value=None) dans le jar, et httpx.Cookies.__getitem__ lève KeyError pour lui. dict(resp.cookies) échouait donc sur un nom que l’itérateur même du mapping avait produit : tech-detect sortait avec le code 1 et un simple error: 'Secure', sans JSON sur stdout, pour une page pourtant récupérée avec succès ; le MCP seo_tech_detect relançait cette KeyError à son appelant, et site-audit renvoyait silencieusement une section technologies absente. detect_tech parcourt désormais le jar de cookies. Un nom sans valeur est conservé avec une valeur vide plutôt qu’abandonné, car plusieurs empreintes (BITRIX_SM_GUEST_ID, craft_session, wfvt_) ne reconnaissent un cookie que par son nom, et l’abandonner ferait perdre ce signal. Mais il n’est jamais normalisé silencieusement en cookie ordinaire : les noms sont signalés dans malformed_cookies et cités dans un constat, de sorte qu’un en-tête mal formé envoyé par le site reste un fait sur le site. Une réponse ne contenant que des cookies bien formés n’est pas affectée et renvoie une liste vide.

  • ModifiéFonctionnerender-check mesure de nouveau les sites compressés au lieu de les déclarer cassés

    (#650).

    La route de rendu épinglée lisait l’origine via le flux brut non décodé de httpx et transmettait ces octets à Playwright avec le content-encoding de l’origine. route.fulfill n’applique jamais un codage de contenu au corps qu’on lui donne : Chromium interprétait le gzip comme du text/html et construisait un DOM à partir du flux compressé, sans title, sans h1, sans canonical, sans liens, avec une taille rendue égale à celle du transfert. Tout site qui compresse son HTML, c’est-à-dire presque tous, sortait avec ok: false, reason: incomplete_render, et le message accusait le rendu en suggérant --wait domcontentloaded ou un --timeout plus long, alors que le rendu était parfaitement terminé. seohead.tech annonçait 22 435 octets rendus contre 121 793 bruts ; il en annonce désormais 123 048, avec le vrai title et 31 liens. La route lit désormais l’entité décodée, retire content-encoding de ce qu’elle transmet (content-length était déjà retiré comme hop-by-hop, donc Playwright annonce la longueur du corps réellement reçu), et ne demande à l’origine que les codages que ce client sait décoder, au lieu de relayer l’invitation de Chromium à br et zstd. Un codage qui arrive quand même non décodé interrompt la requête en le nommant, car le laisser passer reproduirait le bogue en silence. Le plafond d’octets compte désormais les octets décodés, c’est-à-dire le corps que voit le moteur de rendu : une bombe de compression passait auparavant le plafond sous sa forme compressée.

  • ModifiéFonctionneLecture d’Open Graph sur un crawl natif, avec la clé que le parseur écrit réellement

    (#646).

    parse_html enregistre chaque balise sous son nom de propriété complet, {"og:title": ...}, comme l’indique sa docstring, et crawl/collect.py interrogeait le même dict avec "title", "description" et "image". dict.get répondait None à chaque fois : og_title, og_description et og_image étaient vides sur chaque page de chaque crawl natif jamais lancé. Lors du run qui a révélé le problème, 0 page sur 40 920 en portait une, sur un site dont les pages publient pourtant Open Graph. C’est la règle centrale du dépôt inversée : un champ non mesuré lu comme mesuré. Le défaut s’est propagé, car crawl/evidence.py projette ces colonnes dans OG:Title, OG:Description et OG:Image de la trame Internal:All : un contrôle voyait du vide sur un crawl natif et la vraie valeur sur un export Screaming Frog du même site. Le contrat d’honnêteté de check_og masquait le dégât au lieu de le montrer : sans colonne OG renseignée nulle part, il passait en « ignoré », si bien qu’un site avec Open Graph s’auditait exactement comme un site sans. Le parseur est inchangé ; seul le côté lecture a bougé. Un nouveau tests/test_open_graph_seam.py crawle deux sites de test en loopback et suit la valeur du parseur jusqu’à pages.jsonl, puis à la table pages de l’artefact de scan, puis aux colonnes OG:* de la trame. Il crawle un second site sans Open Graph pour distinguer « vide parce qu’absent » de « vide parce que non lu », et fixe la forme des clés du parseur dans le même fichier. La panne tenait à deux modules corrects en désaccord sur un nom de clé, sans test qui couvre les deux.

  • ModifiéFonctionneRépondre à « ce site est-il bien maillé, et où le maillage est-il défaillant » : le

    registre passe de 157 à 161 contrôles, avec une skill internal-linking…

    Répondre à « ce site est-il bien maillé, et où le maillage est-il défaillant » : le registre passe de 157 à 161 contrôles, avec une skill internal-linking (#634). Les éléments existaient (chaque arête avec sa position, son ancre et son drapeau nofollow dans la table links, ORPHAN_PAGE, INLINK_BOILERPLATE_ONLY, LOW_LINK_SCORE), mais rien ne les transformait en réponse sur le graphe. Un audit de 40 920 pages a affiché pendant des heures le mauvais titre à cause de cela : 66 % du sitemap était signalé inatteignable par les liens internes, chiffre produit en soustrayant le nombre d’URL du crawl à celui du sitemap, ce qui mesure « le crawler n’y est pas arrivé ». En parcourant les 5 252 235 arêtes de l’artefact depuis la page d’accueil, l’atteignabilité ressort à 91,9 %. Le vrai défaut était la profondeur : 23 742 pages, soit 58 % du site, se trouvaient à plus de dix clics de l’accueil, et la plus profonde à 3 005, parce que l’archive est une liste chaînée de liens « article suivant » plutôt qu’un arbre. La profondeur de clic est désormais le titre affiché par l’audit. summary.internal_linking porte l’histogramme, le maximum, la répartition atteignable/inatteignable, les arêtes internes par position de page et le nombre d’arêtes qui en répètent une autre, et audit.md l’affiche à côté du résumé de santé. Le parcours part de l’URL à partir de laquelle le crawl a réellement commencé, jamais de pages.crawl_depth : cette colonne enregistre où le crawler est tombé sur une URL, et un crawl amorcé par sitemap y inscrit 0 pour la plupart des pages, donc un parcours amorcé depuis elle décrirait un autre endroit. Si aucune URL de départ n’a été enregistrée et que plus d’une page revendique la profondeur 0, la mesure refuse de tourner et dit laquelle.

  • ModifiéFonctionneQuatre contrôles lisent ces chiffres.

    DEEP_CLICK_DEPTH se déclenche sur une page indexable dont le plus court chemin depuis l’URL de départ dépasse thresholds.click_depth_max (10 par défaut ; chaque constat cite le nombre utilisé). DUPLICATE_INTERNAL_LINK se déclenche sur une page qui écrit plusieurs fois la même destination et la même ancre : sur le site ci-dessus, 509 744 arêtes sur 1 134 307, soit 44,9 %, étaient des répétitions. Il s’agissait d’un même bandeau émis deux fois, la seconde copie étant supprimée par JavaScript, un défaut de gabarit qu’il a fallu un script écrit à la main pour trouver. LINK_INSIDE_HEADING et IMAGE_LINK_WITHOUT_TEXT ont besoin de ce que la zone de page d’un lien ne peut pas porter : la chaîne d’ancêtres de l’ancre et son contenu. Un crawl natif enregistre donc désormais un link_placement_json par page, petit et plafonné, à côté du plan des titres, et ces deux contrôles passent par leur nom sur un export Screaming Frog au lieu de tourner à vide.

  • ModifiéFonctionneLes règles d’honnêteté du reste de l’analyseur s’appliquent partout.

    Une arête sans position enregistrée est comptée en unclassified et n’est jamais rattachée à content : link_position.classify est désactivé par défaut, ce qui laisse chaque arête dans cet état, et une exécution dans cet état doit se lire comme « personne n’a regardé », non comme un site dont tous les liens sont du texte de corps. Une position absente de la distribution est rapportée comme « aucune arête classée ici », et non comme une zone qui manque au site, car les règles sont essayées dans l’ordre et un menu dans <header> correspond d’abord à nav. Un crawl partiel retire le verdict de profondeur de clic, qu’il ait déclenché ou non, parce qu’une frontière jamais récupérée peut contenir le chemin plus court ; un contrôle ne trouvant rien en silence se lirait comme « toutes les pages sont dans le seuil ».

  • CorrigéFonctionneNe plus déclarer propre un contrôle conditionné par une exigence, lorsqu’il n’a jamais

    été évalué (#635).

    H2_MISSING ne se déclenche que si une configuration définit requirements.require_h2, et la valeur par défaut est false : sur un run ordinaire, sa branche est inatteignable. Cela ne laissait aucune trace. La couverture le comptait parmi les contrôles silencieux, la catégorie qui signifie « passé sur chaque page sans rien trouver », et le lecteur apprenait que le site avait réussi un contrôle que personne n’avait exécuté. Sur l’audit qui a révélé le problème, 61 % des pages du site n’avaient aucun H2, et 5 066 d’entre elles dépassaient 800 mots : le contrôle se serait déclenché des milliers de fois. Il est désormais déclaré ignoré par son nom, avec une raison qui cite le réglage qui l’a désactivé. La réponse est donc « non évalué, et voici comment l’évaluer », au lieu d’un silence. require_canonical a la même forme et reçoit le même traitement ; sa valeur par défaut étant true, il ne produisait pas encore une lecture fausse, mais il ne pouvait plus commencer à le faire.

  • CorrigéFonctionneCorrection du titre du backlog de tâches affichant « Audit Tasks – None » pour tout audit

    dont le run…

    Correction du titre du backlog de tâches qui affichait « Audit Tasks – None » pour tout audit dont le run n’avait enregistré aucun projet (#640). render_tasks_md construisait le titre avec src.get("project", "site"), mais "project" est toujours une clé présente dans le bloc source du backlog : elle est définie à la construction à partir de run.get("project"), donc un run sans projet stocke la valeur None au lieu de laisser la clé absente, et la valeur par défaut de dict.get ne s’applique qu’à une clé manquante, jamais à une clé contenant None. Un crawl natif comme une réanalyse laissant project vide, chaque backlog produit à partir de l’un ou de l’autre recevait pour titre le mot « None » littéral. Le titre retombe désormais sur or, qui attrape bien un None stocké, puis cherche l’URL de départ (start_url) ou la source (source) avant d’abandonner. C’est le même ordre que seohead.reports.facts.crawl_domain utilisait déjà pour nommer un site à partir de son bloc run ; cette fonction est désormais exportée et réutilisée ici au lieu d’être réinventée, si bien qu’un backlog issu d’un audit sans projet nomme le site réel au lieu du mot « site ». seohead.reports._normalize_sf_audit avait la même forme latente une ligne plus loin (run.get("project") or "", dans reports/__init__.py) : déjà protégée contre un None stocké, mais son repli était un domaine vide au lieu de l’URL que le run connaît aussi. Le titre « SEO Audit: » des documents docx et md devenait donc vide dans les mêmes situations. Il passe désormais par la même résolution crawl_domain.

  • ModifiéFonctionneLecture du plan des titres comme séquence et comme carte de la page : le registre passe

    de 155 à 157 contrôles (#632). Les huit contrôles existants sur les titres les jugent comme un ensemble : ils peuvent dire qu’une page a un H1 et quatre H2, et rien de plus. Une page dont l’ordre DOM est H2, H2, ..., H1, H2 satisfaisait donc tous ces contrôles, tout comme une page dont les H2 étaient tous des libellés de menu dans son bandeau. Ce cas a été constaté sur un site réel : un gabarit d’article avec dix-huit titres placés avant son propre H1, signalé propre pour les titres. Il manquait la preuve, non la règle : pages stockait h1, h1_2 et h2, soit trois chaînes sans ordre ni place. Un crawl natif enregistre désormais tout le plan h1 à h6 dans l’ordre du DOM, chaque titre avec son niveau, son texte et sa zone de page, dans une nouvelle colonne nullable heading_outline_json, et HEADING_BEFORE_H1 et HEADING_IN_PAGE_CHROME le lisent. La zone réutilise la taxonomie déjà utilisée pour classer les liens (nav, header, sidebar, footer, content, other), de sorte que « dans l’en-tête » signifie la même chose pour un titre que pour un lien. Un titre qu’aucune règle de position ne reconnaît n’est placé dans la zone de contenu que si le document en nomme une : un <main>, un [role=main], un <article> ou un sélecteur configuré. Quand la racine de contenu retombe sur le <body> entier, qualifier un titre de « contenu » ne voudrait pas dire plus que « quelque part sur la page ». La zone est donc enregistrée comme non mesurée, et la page est citée parmi les contrôles ignorés du run avec cette raison, plutôt que déclarée propre ou signalée comme défaut. L’ordre ne demande pas de zone, donc HEADING_BEFORE_H1 répond toujours pour ces pages. Un export Screaming Frog ne contient aucun plan, et les deux contrôles y sont ignorés par leur nom.

  • CorrigéFonctionneConserver une collecte terminée lorsque l’audit qui suit plante (#627).

    Un crawl natif d’un site en production a passé vingt minutes à rassembler 600 pages dans un artefact --scan-out, puis a affiché error: 'rel_next_2' : la str() d’une KeyError est la clé et rien d’autre. Ni phase, ni traceback, ni signe que chaque page collectée se trouvait complète et réanalysable dans le fichier. La collecte enregistre ses lignes et se referme avant le début de l’audit, donc toute exception levée après ce point relève de l’analyseur et jamais du crawl. Une exception inattendue à cet endroit est désormais nommée par phase, porte le type de l’exception en plus de son message, et renvoie vers l’artefact conservé ainsi que la commande qui le réanalyse, exactement comme le chemin des audits trop volumineux le faisait déjà. Le run signale audit_available: false avec cette raison au lieu de quitter sur l’exception, et crawl-site sort avec le code 2. C’est la troisième réponse déjà utilisée pour la contradiction du log-scan : 0 se lirait comme « l’audit a tourné et a trouvé ceci », et 1 comme « la commande n’a rien produit », et aucune de ces deux lectures n’est vraie pour un crawl dont les preuves ont survécu. La KeyError elle-même ne s’est pas reproduite : la même commande sur le même site, sur la branche principale actuelle, s’est terminée. Cela modifie donc ce qui se passe quand un audit échoue, et non ce qui a provoqué cet échec.

  • CorrigéFonctionneNe plus perdre l’audit d’un crawl terminé à cause d’un budget d’inspection fixe de 30

    secondes à la réouverture (#631).

    NativeScan.open() lit l’en-tête d’un scan natif via inspect(), qui exécute aussi PRAGMA quick_check et PRAGMA foreign_key_check sur toute la base. C’est un vrai contrôle de sûreté, mais dont le coût croît avec l’artefact alors que le budget, lui, ne croissait pas. Un crawl de 3 h 30 et 40 920 pages, qui avait fini de collecter tout ce qu’il devait collecter, n’a produit aucun audit : rouvrir l’artefact résultant de 1 Go demandait environ 48 secondes de validation, contre un budget fixé à 30. Pire, l’échec ne laissait aucune raison de soupçonner un budget. L’abandon à l’échéance remonte de SQLite sous la forme nue sqlite3.OperationalError("interrupted"), enveloppée telle quelle en cannot inspect native scan: interrupted, indiscernable d’un fichier réellement corrompu. Les deux points sont corrigés. Le budget par défaut dérive désormais de la taille de l’artefact : un plancher de 30 secondes pour les petits fichiers, plus une marge généreuse par octet, bien en deçà du débit de validation mesuré d’environ 22 Mo/s, puisqu’il s’agit d’un plafond contre une lecture bloquée et non d’un objectif de performance. Un timeout_seconds explicite fourni par l’appelant l’emporte toujours. Un abandon à l’échéance lève désormais une ScanError qui nomme le budget, le temps écoulé et la taille de l’artefact, afin qu’un opérateur distingue un gros fichier lent d’un fichier corrompu, au lieu de lire « interrupted » comme une erreur de sa part.

  • AjoutéFonctionneAjout de crawl-site --resume <scan.sqlite> (#619).

    NativeScan.resume_snapshot(), la table resume_state et le writer qui la remplit existaient depuis la conception de l’artefact de scan, et crawl_to_scan poursuivait déjà un fichier existant. Mais cela ne valait que pour un appelant qui reproduisait octet pour octet les réglages effectifs d’origine, et aucune interface ne le permettait. Pointer --scan-out vers un artefact interrompu avec un seul drapeau modifié était refusé comme incohérence de configuration ; en pratique, un crawl interrompu (6 516 pages sur 34 635, sur le site de quelqu’un d’autre) devait repartir de zéro. --resume prend l’artefact et rien d’autre : l’URL de départ et la configuration effective complète sont relues depuis le fichier, car c’est sur elles que la frontière stockée a été construite. Tout autre drapeau modifiant le crawl passé avec lui est refusé plutôt qu’appliqué. Un scan produit par une autre version, enregistré pour une autre URL de départ, déjà terminé, dérivé d’une réanalyse, ou crawlé avec des en-têtes d’identifiants qu’il ne peut stocker que masqués, est refusé par son nom à partir du seul fichier, avant qu’une requête ne soit envoyée. crawl-site affiche désormais aussi une ligne sur stderr à la sortie, indiquant si le crawl s’est terminé ou arrêté prématurément, pourquoi, et comment le reprendre. Font exception les arrêts après un budget d’URL ou de durée, que la reprise relit aussi et ne peut donc pas passer : la ligne le dit alors au lieu de proposer une commande sans effet. run.crawl_resumed reste l’enregistrement durable : un crawl repris du site de test hors ligne récupère chaque URL exactement une fois à travers les deux processus, et produit un audit identique à celui d’un crawl sans interruption, dans chaque champ sauf celui-là.

  • CorrigéFonctionneNe plus déclarer propre une page non rendue avec render-check, ni abandonner les

    preuves HTML brut lors d’un rendu raté (#642). Deux conséquences du garde de #623, toutes deux dans render.py. D’abord, un rendu qui a expiré à son jalon de chargement retombe sur la lecture du DOM à domcontentloaded, ce qui est sain en soi. Mais quand aucun script n’avait tourné à ce moment-là, le DOM rendu était égal au HTML brut : le comparateur ne trouvait rien, et le run renvoyait ok: True, js_dependent: False et l’unique constat « Le HTML brut et le DOM rendu sont matériellement équivalents ; le rendu JavaScript ne détermine pas le contenu visible pour le SEO », classé en simple notice, à propos d’une page que personne n’avait rendue. wait_reached enregistrait la vérité, mais le rapport de l’audit de site ne reprend que le texte des constats, donc la vérité n’arrivait jamais. Un run revenu à un jalon antérieur le dit désormais dans la liste des constats elle-même, retient le verdict de conformité, et renvoie js_dependent: None (ce run ne sait pas) au lieu de False. Cela se déclenchait avec le --wait load par défaut, et pas seulement avec un networkidle demandé explicitement. Ensuite, le garde renvoyait son unique énoncé « la comparaison est indisponible » avant d’atteindre la branche de coquille vide, et le retour anticipé de render_check omettait complètement la clé empty_shell. Ainsi, un point de montage vide d’application monopage, que detect_empty_shell() lit dans la réponse serveur brute et qui n’a besoin d’aucun navigateur, était jeté avec le rendu raté. Comme une coquille SPA est précisément la page dont le rendu expire, le constat se perdait justement là où il comptait. Un constat tiré de la moitié brute survit désormais à un rendu inachevé ; seuls les constats tirés de la moitié rendue sont supprimés. Dans un crawl, une sonde de rendu qui n’a abouti à aucun verdict atterrit désormais dans patterns_unprobed avec sa raison (canal de #626), au lieu de compter comme un motif mesuré et jugé sans besoin de rendu.

  • ModifiéFonctionneSignaler un robots.txt illisible comme un fait sur le site, et non comme une erreur

    interne (#629).

    EMPTY_ROBOTS, le substitut que _fetch_robots renvoie chaque fois que robots.txt n’a pas pu être lu, gardait la forme de robots analysé d’avant l’ajout de groupes et de sitemaps au parseur. Le chemin de succès renvoie la forme de parse_robots, seule forme que le contexte robots_summary de l’artefact de scan accepte. Donc en mode --scan-out, un crawl s’interrompait avec native parsed robots summary is invalid dès que robots.txt était injoignable, répondait 429 ou 5xx, redirigeait hors de l’hôte, bouclait, dépassait le budget de sauts, ou renvoyait un corps non text/plain. Il en allait de même pour un simple 404, qui n’est pas une erreur mais le cas RFC 9309 « aucune restriction », le plus fréquent des sept. Les deux issues documentées étaient donc perdues derrière cette seule ligne. Un robots.txt absent autorise de nouveau un crawl sans restriction, et un robots.txt indisponible arrête le run en indiquant laquelle des six façons d’échouer s’est produite. L’ancien mode de crawl par répertoire ne s’en apercevait jamais, car rien ne lisait les anciennes clés. Le défaut a été trouvé sur un site réel dont le robots.txt redirige en 302, pour tout user-agent non reconnu, vers un point de synchronisation de cookies.

  • CorrigéFonctionneCorrection de escalate() qui comptait une sonde de rendu échouée comme « ce motif n’a

    pas besoin de rendu » (#626).

    escalate() échantillonne une URL par motif de gabarit pour décider si ce motif a besoin d’une récupération plus complète, avec rendu JavaScript. Mais quand tous les échantillons d’un motif échouaient à la sonde (échec de lancement du navigateur, délai dépassé, ou rendu incomplet, soit les modes d’échec ordinaires d’un crawl réel), le for/else enregistrait tout de même le motif comme sondé. Il n’était ni escaladé ni listé parmi les motifs que le run n’avait pas pu évaluer. Cela inversait la règle centrale du projet, selon laquelle une preuve manquante ou non mesurée ne doit jamais se lire comme propre : un motif sur lequel on n’avait rien appris était récupéré en statique en silence, et présenté comme un motif réellement mesuré et jugé sans besoin de rendu. EscalationResult signale désormais un tel motif dans patterns_unprobed, aux côtés des motifs coupés par l’échéance déjà suivis là, et enregistre la raison d’échec de la sonde dans le nouveau champ patterns_unprobed_reasons. Un rapport peut ainsi dire « ce motif n’a pas été évalué » au lieu de le laisser entendre. Un motif ayant au moins une sonde réussie n’est pas affecté : cela ne change que ce qui se passe quand toutes les sondes d’un motif renvoient ok: False.

  • CorrigéFonctionneArrêt de la déclaration d’un rendu inachevé comme défaut du site par render-check

    (#623).

    Lorsque le rendu n’a pas abouti, l’instantané rendu revenait sans title, sans h1, sans canonical, avec zéro lien et un cinquième des octets de la réponse brute. Le comparateur lisait cette vacuité comme une preuve sur le site : il émettait « le title change après JavaScript » à propos d’un title que le rendu n’avait jamais lu, et « le canonical est injecté par JavaScript » à propos d’un canonical qu’il n’avait jamais vu. Sur un audit réel, cela faisait quatre faux constats d’affilée, chacun du type qui envoie un développeur chasser un bogue JavaScript inexistant. La paire est désormais jugée avant d’être comparée. Quand la réponse brute contient des repères et que le document rendu n’en contient aucun, pour une fraction seulement de sa taille, la vérification renvoie ok: false avec reason: "incomplete_render", une raison nommée portant les deux tailles en octets, et les deux instantanés à inspecter. Aucun constat n’est émis, et js_dependent: null remplace false, parce que le run ne sait pas. site-audit range cela dans summary.tools_failed, là où appartient un contrôle non mesuré. La détection est volontairement étroite : un seul repère survivant, ou un document rendu d’au moins la moitié de la taille de la réponse brute, est comparé comme avant. Une page sans title ni lien des deux côtés est mesurée et simplement vide, non non mesurée. Un title réellement réécrit par un script déclenche toujours son constat. La stratégie d’attente gère aussi la cause ordinaire : un site dont les scripts d’analytics, de chat ou de publicité en long polling ne laissent jamais le réseau au repos expirait en entier sous --wait networkidle. Il retombe désormais sur la lecture du DOM à domcontentloaded, sans seconde navigation, avec wait_reached indiquant le jalon exact d’où provient l’instantané, plus une courte pause pour les scripts différés. Une page dont DOMContentLoaded ne se déclenche jamais reste un échec de rendu, et non un rendu incomplet.

  • ModifiéFonctionneAjout d’une ligne de progression en direct à crawl-site (#619, volet progression).

    Un crawl natif affichait son taux de requêtes effectif, puis rien du tout jusqu’à la fin. Sur un site de 34 000 pages, la seule façon de savoir qu’il tournait encore était de regarder grossir le fichier de scan avec ls -la. La ligne se rafraîchit désormais sur place dans un TTY : pages récupérées, URL connues jusqu’ici, leur pourcentage, le débit courant sur une fenêtre glissante, le temps écoulé, et la taille de l’artefact de scan quand --scan-out en écrit un. Elle évite délibérément de suggérer un total qu’elle ne peut pas connaître. Un crawler découvre sa propre charge de travail, donc le dénominateur est fetched + queued plafonné au budget d’URL. Il est étiqueté known et non total, et une ligne d’en-tête affichée une seule fois précise que la frontière grossit encore et que le pourcentage n’est pas une estimation de la fin du run. Un débit non mesurable s’affiche rate n/a, jamais 0.0 req/s. Les deux chiffres viennent des structures du crawl lui-même : pour un scan SQLite, de la même requête resume_snapshot que la boucle de collecte utilise pour se diriger. L’écran affiche donc ce que l’artefact contient à cet instant, et non un décompte parallèle susceptible de diverger. Hors TTY (un tube, un fichier journal, la CI), une ligne simple toutes les 30 secondes remplace les redessins avec retour chariot. Une nouvelle option -q/--quiet supprime à la fois la ligne de progression et la ligne de débit au démarrage, en laissant intact le résultat JSON sur stdout.

  • ModifiéFonctionneClôture des trois lignes de pagination laissées ouvertes par #385 : le registre passe de

    152 à 155 contrôles. PAGINATION_MULTIPLE et PAGINATION_URL_NOT_IN_ANCHOR signalent une page qui déclare deux successeurs différents, ou dont l’URL déclarée n’est pas aussi une ancre de la même page. Les successeurs sont comparés après normalisation d’URL, la même identité que la moitié « ancre » utilise. Ainsi /blog/page/2 et /blog/page/2/ venant de deux extensions forment un seul successeur écrit deux fois, et non une série ambiguë. PAGINATION_URL_NOT_IN_ANCHOR a besoin de tout l’inventaire de liens d’une page et lit pour cela l’export All Inlinks. PAGINATION_MULTIPLE n’en a pas besoin : il lit désormais d’abord les colonnes plus légères d’occurrences rel="next" 2 / rel="prev" 2 de Internal:All, comme CANONICAL_MULTIPLE répond déjà à partir de Canonical Link Element 2. All Inlinks n’est qu’un repli pour un profil dont Internal:All a été écrit sans ces colonnes. PAGINATION_SEQUENCE_ERROR signale une rupture dans une suite de numéros de page que la série suit par ailleurs, selon la mise en garde de l’issue elle-même : une série peut commencer à un numéro autre que un, un pas n’est pas une rupture, et une série dont les URL n’indiquent pas de numéro de page est déclarée non évaluée, plutôt que jugée au regard d’une numérotation qu’il aurait fallu inventer. Chaque série laissée sans jugement est citée parmi les contrôles ignorés du run, avec la raison valable pour *cette* série. Un pas, un cycle, une série trop courte pour contenir une suite et un numéro de page illisible sont quatre affirmations différentes, et trois d’entre elles décrivent des séries dont toutes les URL affichent leur numéro. Le décompte se fait par série et non par run, si bien que la forme ordinaire de WordPress (page un à /blog/ sans numéro, les suivantes à /blog/page/N/) ne peut pas disparaître derrière une série jugeable ailleurs sur le même crawl.

  • AjoutéFonctionneAjout d’une garde de couverture des verdicts de contrôle (#98) :

    test_check_producer_gate.py prouvait que chaque contrôle…

    Ajout d’une garde de couverture des verdicts de contrôle (#98). test_check_producer_gate.py prouvait que chaque identifiant de contrôle est enregistré et que chaque fonction check_* est appelée, mais ne disait rien de la question de savoir si la conclusion d’un contrôle avait jamais été démontrée vraie face à un balisage portant réellement le défaut, ni de son silence face à un balisage qui ne le porte pas. C’est exactement la lacune qui a laissé passer #94, #95 et #96 malgré chaque test existant, tout en continuant de se déclencher à tort sur des sites réels. test_check_verdict_coverage.py parcourt tests/ structurellement (AST, et non une liste fixe d’appels) pour les deux moitiés de chaque contrôle. Il fait échouer le build pour tout contrôle nouvellement ajouté au registre sans test bilatéral ni exemption nommée et motivée. Sur les 152 contrôles du registre, 88 avaient déjà une preuve bilatérale. Un nouveau test_check_verdict_gaps.py comble 22 autres lacunes peu coûteuses à tester, révélées par le scan : longueur et duplication des titres et descriptions, duplication de H1, présence de H2, hygiène des URL, contrôles de directives et de balisage, codes de réponse, et les deux contrôles d’exports filtrés natifs. Les 64 restants sont nommés, non cachés, dans le cliquet KNOWN_UNCOVERED de la garde, à réduire au fur et à mesure que la couverture arrive. Cette liste ne doit jamais grandir pour admettre un contrôle ajouté après l’existence de cette garde.

  • CorrigéFonctionneCorrection d’un défaut de sélection de groupe dans robots.txt : une valeur User-agent

    vide annulait la politique par défaut d’un site (#566).

    Une ligne User-agent: nue, ou dont le nom de bot était avalé par un commentaire en ligne (User-agent: # old bot rule), était analysée en jeton vide. _rules_for traitait ce jeton comme n’importe quel nom littéral. C’est un préfixe de longueur zéro de tous les agents, donc il correspondait à tous, et comme il comptait comme une correspondance *nommée*, il l’emportait sur le vrai groupe User-agent: * du fichier pour chaque crawler que le fichier ne mentionnait pas. Un robots.txt dont la seule règle substantielle était User-agent: * / Disallow: / apparaissait donc entièrement explorable, tant dans le rapport d’accès des bots d’IA que dans le filtrage de récupération du crawler lui-même, qui appelle la même is_allowed. Les valeurs User-agent vides sont désormais ignorées : un tel groupe ne nomme personne, et le groupe joker s’applique. Le groupe nommé le plus spécifique l’emporte toujours, et un robots.txt ne nommant personne continue de tout autoriser.

  • CorrigéFonctionneCorrection de quatre défauts de sélection d’export et de validation de run qui laissaient

    un audit présenter un résultat qu’il ne pouvait pas étayer (#209, #210, #215, #216).

    internal_all ne demandait que le jeton de nom de fichier internal, si bien qu’un onglet Internal par type partiel (par ex. internal_html.csv, sans aucune ligne non HTML) satisfaisait l’export maître Internal:All requis sans avertissement de maître manquant. Le filtre exige désormais aussi all. discover_exports prenait le premier candidat pour une clé logique dans l’ordre alphabétique des noms quand deux fichiers correspondaient (par ex. internal_all.csv et internal-all.csv présents avec des lignes différentes), en écartant silencieusement l’autre sans rien dans les métadonnées du run pour signaler qu’un choix avait été fait. Il lève désormais une erreur en nommant chaque candidat. run_sf choisissait le sous-dossier horodaté le plus récent sous --out, quelle que soit sa date de création. Un relancement qui sortait avec le code 0 sans rien écrire (un échec au démarrage que Screaming Frog ne signale pas par un code de sortie non nul) pouvait donc renvoyer les exports d’une invocation antérieure comme s’ils étaient frais. Il compare désormais avec un instantané pris avant le démarrage du processus, et échoue bruyamment si rien de nouveau n’apparaît. build_command n’ajoutait --auth-config que si le fichier de profil donné existait déjà. Il lançait donc silencieusement un crawl non authentifié sur un chemin mal tapé ou supprimé, ce qui est approprié pour le seospiderconfig optionnel par défaut, mais faux pour un profil explicitement demandé par l’appelant. Un sf_cli.auth_config explicite mais absent lève désormais une erreur avant que Screaming Frog ne démarre.

  • CorrigéFonctionneCorrection de deux défauts d’extraction de contenu dans seohead/checks/parser.py (#138,

    #140).

    collapse_whitespace décodait une seconde fois les entités HTML, en plus du décodage unique que le parseur lxml de BeautifulSoup effectue déjà sur chaque valeur que tag.get_text()/tag.get(attr) transmet à cette fonction. Sans effet sur un balisage ordinaire, cela transformait en revanche, sur une page dont le CMS ou la chaîne d’import avait déjà doublement échappé ses entités (un artefact réel et courant), une soupe d’entités visiblement cassée en texte d’apparence propre, et raccourcissait la longueur rapportée en dessous de ce qu’un onglet de navigateur ou un extrait SERP affiche réellement. Cela retournait dans les deux sens les contrôles de longueur des titres et descriptions. La fonction ne décode plus rien. Par ailleurs, l’extraction des liens et des sources d’URL parcourait tout le document sans condition. Un <a> ou un <img> existant seulement à l’intérieur d’un <template> inerte n’est jamais partie du document rendu selon la spécification HTML, et n’est jamais demandé par un navigateur ni par un crawler, à moins qu’un script ne le clone. Pourtant il était signalé comme un vrai lien sur la page, et réellement récupéré par spider.py. C’est le même mode d’échec d’URL fantôme que celui corrigé pour <base href> dans #4 ; les deux extracteurs ignorent désormais les descendants de <template>. <noscript> reste volontairement accessible ici, contrairement à l’extraction de texte : c’est un repli réel, défini par la spécification, qu’un client sans JavaScript (et la passe de crawl sans rendu des moteurs de recherche) charge bel et bien. L’exclure masquerait à l’auditeur une URL réellement récupérable. Le nombre de mots ne compte plus non plus le texte des descendants <svg>/<math> (le <title> d’accessibilité d’un sprite d’icônes, le <text> d’un glyphe, la notation MathML) comme contenu : un en-tête de 20 icônes pouvait doubler le nombre de mots rapporté par rapport au contenu réel. Cette liste d’exclusion vit désormais en un seul endroit, content_area.TEXT_EXCLUDED_TAGS, partagé par les deux extracteurs de texte, au lieu de deux copies qui avaient déjà divergé.

  • CorrigéFonctionneConserver les jetons rel complets d’un lien, son attribut target et son href brut

    (avant résolution), et extraire les éléments <form> : méthode, action, présence d’un champ mot de passe (#125). Six problèmes catalogués dépendaient de la conservation de ces trois éléments, qui était jusqu’ici jetés : les liens cross-origin peu sûrs (target="_blank" sans rel="noopener"/"noreferrer"), les liens protocol-relative (//host/path, avant résolution), les liens sortants vers localhost, une page recevant à la fois un lien interne suivi et un lien nofollow, une action de formulaire non sécurisée, et un formulaire de mot de passe servi depuis une page HTTP en clair. Les six sont désormais UNSAFE_CROSS_ORIGIN_LINK, PROTOCOL_RELATIVE_LINK, OUTLINK_TO_LOCALHOST, FOLLOW_AND_NOFOLLOW_INLINKS, FORM_URL_INSECURE et FORM_ON_HTTP_URL dans le registre. Les contrôles de formulaire, de localhost et de mélange nofollow n’ont besoin que de champs déjà enregistrés par chaque crawl : ces quatre-là s’exécutent sans condition. La paire cross-origin et protocol-relative demande link_attributes.capture, désactivé par défaut, car les données supplémentaires par arête ont mesuré environ +50 % sur un crawl synthétique de 3 387 pages avec 150 liens par page, soit environ +95 octets par arête et +46 Mo au total, raw_href représentant l’essentiel. Le registre passe de 121 à 127 contrôles.

  • CorrigéFonctionneCorrection de report-build qui rendait silencieusement un rapport sans aucun constat

    pour un audit SF Analyzer…

    Correction de report-build qui rendait silencieusement un rapport sans aucun constat pour un audit.json de SF Analyzer (#151). La recette documentée, sf run --tasks routé vers report-build --format docx/xlsx/csv/md, lisait les clés plates findings et les pages, que le schéma SF n’utilise pas : les constats sont sous issues, les faits de page sous pages[].metrics. L’écart produisait un résumé 0/0/0/0 assuré pour un audit qui avait bel et bien trouvé des problèmes critiques, sans aucune section de constats. build_report reconnaît désormais la forme native seohead.site-audit/1 et la forme SF Analyzer, et normalise cette dernière en contrat plat que les quatre rédacteurs destinés aux lecteurs comprennent déjà, avant le rendu. --format json est inchangé : il relayait déjà correctement le document d’origine, ce qui prouvait que les données n’avaient jamais manqué. Un document qui ne correspond à aucun des deux contrats est refusé avec ok: False en nommant l’écart de schéma, au lieu d’être rendu comme un livrable vide. La condition morte if ... : pass, qui ressemblait à une validation mais ne faisait jamais rien, a disparu. tests/test_docs_commands_execute.py vérifie désormais le résumé rendu de la recette documentée contre les totaux propres de audit.json, et pas seulement son code de sortie.

  • ModifiéFonctionneFermeture de deux lacunes de sécurité financière dans seohead/data_sources/ (#157,

    #159).

    geo_guard ne contrôlait que la chaîne de pays consultative country. search_volume, keyword_ideas, keyword_difficulty et serp pouvaient donc quand même atteindre le point d’accès en direct de DataForSEO pour location_code=2643 (Russie) ou 2112 (Biélorussie) dès qu’un appelant fournissait le code géographique numérique sans renseigner country. Le garde vérifie désormais location_code en premier, puisque c’est le champ effectivement facturé. Par ailleurs, une exception réseau (URLError/TimeoutError/SSLError) pendant un appel facturé relançait la charge utile identique sans clé d’idempotence. C’était le cas du post de DataForSEO, du /set d’Arsenkin, et de wordstat.topRequests/wordstat.dynamics/web.searchAsync de Yandex Cloud, qui ne journalisaient que la tentative finissant par renvoyer une réponse. Aucun des trois fournisseurs n’offre de mécanisme d’idempotence pour ces points d’accès. Une réponse perdue n’est donc plus relancée : la tentative est enregistrée dans le registre des dépenses (coût inconnu, marqué attempt_failed: network_error) et l’appel échoue purement et simplement, au lieu de risquer un second débit. Les lectures idempotentes (/check et /get d’Arsenkin, interrogation des opérations Yandex Cloud) ne sont pas touchées et continuent de relancer. yandex_cloud.WebSearch.search_batch isole désormais une soumission perdue à sa propre requête au lieu d’abandonner le lot. metrika.py relance les erreurs réseau de la même façon, mais ce n’est pas un coût monétaire et il n’a pas été modifié. À reprendre si la création de son export Logs API doit recevoir le même traitement pour des raisons de quota.

  • ModifiéFonctionneFermeture d’une faille de DNS rebinding dans http_client() (#142) : pinned_target(),

    correctif de la fenêtre TOCTOU de #14…

    Fermeture d’une faille de DNS rebinding dans http_client() (#142) : pinned_target(), correctif de la fenêtre TOCTOU décrite dans #14, ne protégeait que la récupération en mode liste de collect.py. Les quatorze autres points d’appel, y compris le moteur crawl-site de spider.py, laissaient httpx résoudre le DNS une seconde fois, indépendamment, pour ouvrir le socket. Un résolveur hostile répondant différemment à cette seconde requête pouvait donc atteindre 169.254.169.254 ou une adresse RFC 1918, quel que soit le verdict du garde. http_client() construit désormais chaque client sur un transport qui épingle la connexion à l’adresse qu’il résout lui-même, à la première requête et à chaque saut de redirection, en ne gardant le nom d’hôte que pour l’en-tête Host et le SNI TLS. La correction est donc structurelle, et non une discipline que chaque appelant devait retenir. SEOHEAD_ALLOW_PRIVATE_NETWORKS/SEOHEAD_ALLOW_PRIVATE_HOSTS restent inchangés.

  • CorrigéFonctionneCorrection du contrat de code de sortie CLI/MCP pour un échec signalé par un handler

    lui-même, et complétion de SOURCE_FLAGS (#155, #156). Un handler renvoyant {"ok": false, ...}, la façon documentée qu’a la couche outils de signaler un échec de récupération, d’analyse ou de fournisseur sans lever d’exception, affichait ce JSON et sortait avec le code 0 en CLI. Via MCP, il renvoyait un résultat normal, sans isError. Un pipeline testant $? ou un client ne vérifiant que isError ne pouvaient donc pas détecter l’échec. cli.py sort désormais avec le code 1 dans ce cas. Le code 2 de log-scan pour un run qui se contredit reste un signal distinct et documenté (voir docs/USAGE.md). mcp_server.py lève ToolError depuis un wrapper partagé _checked(), de sorte qu’un client voit isError. Les deux appellent une même handlers.handler_failed(), pour que les deux interfaces ne divergent pas sur ce qui compte comme un échec. Par ailleurs, SOURCE_FLAGS a gagné --phrase, --keywords, --query/--queries, --seed, --counter, et --before/--after. Chacun identifie déjà l’entrée complète d’une commande, comme le fait --url, mais il manquait : une boucle ligne par ligne sur l’un d’eux ne traitait donc silencieusement que sa première ligne. L’ensemble est désormais construit par _source_flag() au moment où chaque drapeau est déclaré, au lieu d’être listé à la main à part, ce qui l’empêche de diverger à nouveau.

  • ModifiéFonctionneExtension de docs/scenarios/ de dix enchaînements à cinquante-six, regroupés par la

    question que se pose le lecteur à son arrivée (#120). Les scénarios retenus sont fixés par la carte de couverture, et non par goût : chacun déclare les problèmes catalogués qu’il résout. tests/test_scenario_coverage.py vérifie que chaque problème que cet outil prétend trouver figure dans au moins un scénario, qu’aucun scénario ne cite un problème absent de la carte, et qu’aucun n’omet ses limites. Les 143 problèmes repérables sont tous couverts. Chaque commande de chaque fichier est toujours exécutée sur le site de test en CI. La suite compte 2 008 tests, dont la garde des commandes de documentation est désormais le plus gros groupe.

  • ModifiéFonctionneVérification des limites propres au protocole sitemap (#124) : SITEMAP_TOO_MANY_URLS

    au-delà de 50 000 entrées dans un seul fichier, SITEMAP_TOO_LARGE au-delà de 50 Mo non compressés, et SITEMAP_URL_DUPLICATED pour une URL déclarée dans plus d’un sitemap, en nommant les deux documents. Un fichier qui dépasse l’une de ces limites est invalide, et non simplement volumineux : un moteur de recherche peut en lire une partie et écarter le reste sans que le propriétaire du site le voie. Les seuils viennent du protocole, non de la configuration. Les deux parseurs enregistrent désormais la taille en octets et le nombre déclaré de chaque document, et les constats nomment le sitemap enfant plutôt que l’index. Le registre passe de 118 à 121 contrôles.

  • AjoutéFonctionneAjout de docs/GUIDELINE.md, le document à lire en premier (#121) : ce que c’est, ce que

    ce n’est pas…

    Ajout de docs/GUIDELINE.md, le document à lire en premier (#121) : ce que c’est et ce que ce n’est pas, une première exécution de bout en bout, comment choisir un débit de crawl et comment savoir si les erreurs viennent de vous, comment lire audit.json sans s’y laisser induire, ce que le fichier de configuration modifie et ce qu’il ne fait que coûter, les six erreurs que tout le monde commet au début, quoi faire quand l’outil se trompe, et ce à quoi il ne peut pas répondre du tout. Il est lié en premier depuis le README, avant la référence.

  • AjoutéFonctionneAjout de docs/COVERAGE_SF_ISSUES.md, généré à partir de

    seohead/sf/core/sf_issue_map.py : chacun des 320 problèmes du catalogue publié du domaine, avec un statut unique. Ce statut est soit « trouvé par un contrôle nommé », soit « trouvé par une commande nommée », soit « trouvé en partie, avec la part manquante indiquée », soit une lacune nommée, soit une décision motivée (#119). Sur les 212 problèmes dans le périmètre, 126 sont trouvés aujourd’hui et 17 en partie ; 41 sont des lacunes et 28 nécessitent quelque chose délibérément non construit. L’accessibilité (92) et AMP (16) sont écartées par décision unique, avec leurs listes complètes affichées pour que la décision soit vérifiable. Un test vérifie que chaque identifiant de contrôle et chaque commande référencés existent encore : un renommage casse donc le build au lieu de laisser le document périmer. Remplace docs/CHECKLIST_AUDIT.md, rédigé sans le catalogue sous les yeux.

  • ModifiéFonctionneLe seeder de sitemap demande l’adresse publiée par le sitemap, et non sa forme normalisée

    (#115). sitemap.crawl() ne renvoyait que le loc normalisé : un sitemap déclarant /a/ provoquait la récupération de /a. Sur la plupart des CMS, c’était une redirection 301 que le crawler inventait puis rapportait comme un fait sur le site, et un 404 partout où la forme sans slash n’est pas routée. Chaque entrée porte désormais loc tel que publié, accompagné de loc_normalized pour les consommateurs qui comparent sur celui-ci. Les statistiques de redirection des crawls précédents amorcés par sitemap sont suspectes pour cette raison.

  • ModifiéFonctionneRestructuration de la skill opérateur en répertoire contrôleur (#111).

    .claude/skills/ comporte désormais deux niveaux : 21 skills de méthode, chacune couvrant une chose bien, et control/, qui décide lesquelles lancer sur un site que personne n’a encore examiné. Le contrôleur route au lieu de reformuler. Il contient cinq sous-skills chargeables (cadrage, débit et charge, lecture d’un audit, vérification, livrables) ainsi qu’une archive de référence en trois fichiers : défauts trouvés sur des sites réels et ce qui a permis de les repérer, population que décrit chaque contrôle, et ce à quoi l’outil ne peut pas répondre du tout. La garde de langue anglaise seule et la garde des commandes de documentation couvrent désormais chaque fichier Markdown sous un répertoire de skill, et plus seulement SKILL.md.

  • AjoutéFonctionneAjout de tests/chains/ : un site de test construit à partir des formes qui cassent

    réellement les enchaînements —…

    Ajout de tests/chains/ : un site de test construit à partir des formes qui cassent réellement les enchaînements (les deux formes avec et sans slash final d’une même URL, un corps qui n’est pas de l’UTF-8 valide, une page en windows-1251, un bandeau hors de <main>, un lien vers un autre hôte, un chemin interdit par robots.txt). Il est exploré en loopback, avec dix-sept assertions portant sur l’exécution dans son ensemble plutôt que sur un module donné (#112). Quatre propriétés sont testées : conservation (un nombre ne change pas de sens en traversant le pipeline), population (un constat porte sur un membre de l’ensemble qu’il décrit), déterminisme (deux crawls, deux niveaux de concurrence, une seule réponse) et représentation (une page indique comment elle a été mesurée). Les règles de population sont celles de logscan lui-même : une contradiction que le scanner sait nommer est une assertion de ce test d’enchaînement.

  • ModifiéFonctionnereconcile_sitemap signale chaque URL telle qu’elle a été écrite, et non telle qu’elle a

    été normalisée.

    La comparaison se fait toujours sur la clé normalisée. Mais un constat qui nommait une forme normalisée désignait une URL n’apparaissant nulle part dans le crawl : inexploitable pour un lecteur, et indiscernable, pour le scanner d’anomalies, d’un constat sur une page jamais récupérée.

  • AjoutéFonctionneAjout de docs/scenarios/ : dix enchaînements de bout en bout, chacun avec les vraies

    commandes dans l’ordre, l’artefact produit, son coût, et ce que cet enchaînement ne peut pas répondre (#110). Le reste de la documentation liste ce que l’outil contient ; celle-ci décrit ce qu’il fait. Lien depuis le README, au-dessus de la liste des outils, pour qu’un agent qui évalue le dépôt trouve les enchaînements avant l’inventaire. Chaque commande présentée est exécutée sur le site de test par tests/test_docs_commands_execute.py, dont l’extracteur et les gardes de langue anglaise seule et de comptage parcourent désormais docs/ à tous les niveaux, et plus seulement son premier niveau.

  • AjoutéFonctionneAjout de log-scan (CLI) et de seo_log_scan (MCP) : lire les artefacts d’un run

    terminé et signaler les affirmations incompatibles entre elles…

    Ajout de log-scan (CLI) et de seo_log_scan (MCP) : lire les artefacts propres d’un run terminé et signaler les affirmations qui ne peuvent pas être toutes vraies à la fois (#109). Huit règles, chacune écrite à partir d’un défaut livré malgré toute la suite de tests : une taille enregistrée en désaccord avec le fichier sur le disque, un ratio de texte supérieur à 100 %, un contrôle qui se déclenche plus souvent qu’il n’y a de pages sur lesquelles le faire, un constat sur une URL que le run n’a jamais récupérée, une canonical traitée comme une redirection alors que cette URL répondait 2xx dans le même run, un résumé en désaccord avec ses propres lignes, des mots comptés sur une page de zéro octet, et des pages mesurées de deux façons où seules certaines précisent laquelle. Chaque anomalie nomme les deux valeurs et l’endroit où chacune a été lue. La CLI sort avec le code 2 lorsqu’un run se contredit, afin qu’un pipeline s’arrête au lieu de publier les chiffres.

  • ModifiéFonctionneLe test de cadencement entre workers ne mesure plus l’horloge murale (#107).

    _DispatchGate lit désormais l’horloge injectée du crawl au lieu de time.monotonic() directement. Le test le pilote avec une horloge virtuelle qui n’avance que lorsque quelque chose dort, de sorte que les instants d’envoi sont l’arithmétique du crawler lui-même et que l’assertion est exacte. L’ancienne forme comparait les écarts réels écoulés à un plancher de 0,024 s, et échouait sur un code inchangé chaque fois que la machine était occupée.

  • ModifiéFonctionneFermeture de la seconde moitié de l’audit des réglages non branchés (#91).

    http.headers est fusionné dans chaque requête à côté des en-têtes d’identifiants. speed.adaptive contrôle le délai du throttle et l’ajustement de la concurrence ; les compteurs de timeout et d’erreurs serveur continuent de tourner, car abandonner est un mécanisme distinct du ralentissement. discovery.hyperlinks.store / .crawl, discovery.external.store et discovery.redirects.crawl déterminent désormais ce que le crawl enregistre et ce qu’il suit. discovery.canonicals.*, discovery.external.crawl et discovery.redirects.store sont supprimés au lieu d’être câblés : ils désignaient une capacité que le spider n’a pas (suivre les canonical, explorer d’autres hôtes) ou un état qu’il ne peut pas retenir. Un réglage qui apparaît dans --config-help et dans le manifeste de run sans rien changer vaut moins que l’absence de réglage. La liste d’exemptions du témoin de couverture est désormais vide : chaque chemin de DEFAULTS modifie un résultat observable et est nommé par un test.

  • ModifiéFonctionneDétecter la zone de contenu à partir de la sémantique du document quand rien n'est

    configuré (#96) : main, puis [role="main"], puis article, en enregistrant lequel a correspondu sous auto_main / auto_role_main / auto_article. L'ancien défaut, à savoir tout le body moins les balises nav et footer, comptait 126 mots de gabarit sur 433 dans un article WordPress réel (29 %), dont un lien d'accès rapide au contenu. Cette surestimation alimentait THIN_CONTENT et LOW_TEXT_RATIO dans le même sens sur chaque page d'un gabarit. header et aside rejoignent nav et footer dans DEFAULT_EXCLUDE_TAGS pour le chemin de repli. Un sélecteur configuré reste prioritaire, et un sélecteur qui ne correspond à rien revient toujours à fallback_default_body au lieu de détecter silencieusement une autre zone.

  • ModifiéFonctionneURL_NOT_IN_SITEMAP compare désormais des pages avec des pages (#94).

    Il comparait les URL d'un sitemap à chaque destination du graphe de liens du crawl. Sur un site réel de 124 pages, la règle se déclenchait donc 392 fois : 362 fichiers image qu'une galerie lie directement, cinq liens vers d'autres hôtes et 30 URL que le crawl n'avait jamais récupérées. Cela représentait 74 % de ce rapport et masquait les constats réels. Le côté observé ne contient plus que les pages qu'un sitemap est censé déclarer : récupérées, en 2xx, au format HTML, sur le même hôte et indexables. reconcile_sitemap reçoit cette population dans un argument comparable distinct. SITEMAP_ORPHAN continue donc de vérifier l'accessibilité par rapport à toutes les destinations de liens, sans pouvoir inventer d'orphelines. Ce qui a été mis de côté est renvoyé sous linked_not_comparable au lieu d'être supprimé.

  • CorrigéFonctionneCorriger les contrôles canonical sur un site qui sert les deux formes d'une URL, avec et

    sans slash final (#95).

    norm_url supprime volontairement le slash final, donc une balise canonical écrite sans slash correspond à la page qui en a un. Mais l'index normalisé ne gardait qu'une page par clé, alors qu'un crawl de site WordPress type en contient deux : /x (301) et /x/ (200). Lire celle qui avait été insérée en premier faisait signaler à CANONICAL_TO_REDIRECT 78 pages actives dont la canonical répond 200. AuditContext expose désormais pages_by_norm, qui range toutes les pages sous une même clé, et page_by_norm renvoie la variante qui a répondu en 2xx. CANONICAL_TO_REDIRECT et CANONICAL_NON_INDEXABLE ne se déclenchent que si aucune variante ne les contredit.

  • CorrigéFonctionneCorriger size_bytes : il correspond désormais au corps de la réponse tel qu'il est

    arrivé sur le réseau, mesuré avant décodage (#99). Il était mesuré sur la chaîne décodée, si bien que chaque octet non valide en UTF-8 devenait U+FFFD et était réencodé sur trois octets. Un WebP de 739 Ko issu d'un crawl réel était enregistré à 1,27 Mo, et le facteur de gonflement variait d'un fichier à l'autre. Les images, PDF, polices et HTML servis dans un jeu de caractères historique (windows-1251) étaient tous surestimés, de même que le ratio de texte calculé sur ce dénominateur. Le cache HTTP stocke désormais la taille réseau avec l'entrée, donc une page rejouée affiche la taille relevée lors de la récupération en direct. Son schéma passe à http_cache.v2, et les entrées v1 sont récupérées à nouveau une fois au lieu d'être rejouées sans taille.

  • AjoutéFonctionneAjouter docs/TOOL_REFERENCE.md, généré à partir des définitions d'outils MCP

    (seohead/mcp/tool_reference.py, scripts/generate_tool_reference.py) : pour chaque outil seo_*/sf_*, ses arguments avec leur type et leur valeur par défaut, son coût (réseau, écritures, idempotence, dépense, lu dans son profil ToolAnnotations) et les notes de comportement et de modes d'échec de sa propre docstring. tests/test_docs_drift.py fait échouer le build s'il s'écarte des définitions d'outils ou s'il manque un outil.

  • AjoutéFonctionneAjouter tests/test_docs_commands_execute.py : il extrait chaque commande seohead ...

    présentée dans le README, la documentation, les skills et les exemples (scripts/doc_commands.py), puis exécute chacune hors ligne, sur un site de test en boucle locale (tests/doc_fixtures/) et sur des copies matérialisées de examples/, en vérifiant une sortie propre. Les commandes qui exigent une vraie infrastructure (RDAP/DNS, binaire SF sous licence, identifiants d'un fournisseur payant, serveur mcp qui ne se termine jamais) sont au moins analysées par le parseur d'arguments réel. Une commande documentée qui ne fonctionne plus fait désormais échouer la CI au lieu d'être livrée obsolète.

  • ModifiéFonctionneRefondre les 21 skills de workflow techniques (.claude/skills/*/SKILL.md) selon une

    structure commune : Déclencheur, Anti-déclencheur, Prérequis (sous forme de checklist), le Workflow existant, Points de décision, Définition de terminé (sous forme de checklist) et Coût. Corriger le nombre de commandes obsolète en bas de docs/SKILLS.md : le nombre réel, recalculé en parcourant chaque fichier de skill, est désormais vérifié par un nouveau test de dérive.

  • CorrigéFonctionneCorriger plusieurs compteurs d'outils et de tests qui avaient silencieusement dérivé des

    registres réels (un nombre de commandes CLI obsolète…

    Corriger plusieurs compteurs d'outils et de tests qui avaient silencieusement dérivé des registres réels : nombre de commandes CLI obsolète dans docs/USAGE.md, docs/COMPARISON.md, README.md et docs/TESTING.md, nombre d'outils MCP obsolète dans docs/TOOLS.md, nombre de références d'outils obsolète dans docs/README.md, et nombre de tests hors ligne. Les valeurs corrigées sont figées par un test de régression (test_stale_tool_counts_do_not_reappear).

  • AjoutéFonctionneAjouter les quatre audits Lighthouse statiques qui n'ont besoin ni de navigateur ni d'API

    tierce (#59) : MISSING_CHARSET, MISSING_DOCTYPE, VIEWPORT_MISSING et NO_COMPRESSION, chacun calculé à partir des éléments qu'un crawl détient déjà. content_encoding, meta_charset, doctype et viewport rejoignent le vocabulaire de colonnes normalisées, de sorte qu'un export Screaming Frog qui porte ces valeurs en colonnes d'extraction personnalisée alimente les mêmes contrôles. Le registre passe de 114 à 118 contrôles.

  • ModifiéFonctionneBrancher les dix réglages restants du crawler, validés et écrits dans le manifeste

    d'exécution, mais décrits par --config-help et lus par personne (#63). limits.max_response_bytes, speed.max_delay_seconds, robots.user_agent_token et speed.stop_after_consecutive_timeouts pilotent désormais un comportement qui était codé en dur. robots.unavailable_means_stop détermine si un robots.txt injoignable ou en 5xx arrête le crawl ou est traité comme sans restriction. Auparavant, un robots.txt injoignable n'arrêtait jamais le crawl, quelle que soit la politique, alors qu'un robots.txt en 5xx l'arrêtait toujours. Les deux cas forment désormais un seul cas « indisponible », régi par ce réglage. limits.max_url_length, limits.max_query_variants_per_path, http.retry_on_timeout et discovery.follow_nofollow sont des comportements nouvellement implémentés. http.user_agent est appliqué aux vraies requêtes, au lieu d'envoyer toujours l'user-agent par défaut du toolkit. Ajout de crawl-describe-settings (CLI) et seo_crawl_describe_settings (MCP), pour qu'un agent découvre la surface de configuration sans accès au système de fichiers (#23).

  • AjoutéFonctionneAjouter la recherche personnalisée (tools/custom_search.py) et l'extraction

    personnalisée (tools/custom_extract.py) sur un corpus déjà crawlé : filtres de présence et d'absence (source brute, texte visible, élément CSS nommé ou nœud XPath), ainsi que des extracteurs CSS, XPath et regex. Les deux indiquent sur quelle représentation ils ont travaillé, balisage statique ou DOM rendu. L'absence est comptée honnêtement : une page dont la récupération a échoué est exclue du numérateur comme du dénominateur, au lieu d'être comptée comme manquante. L'extraction exécute chaque couple (document, extracteur) sous un budget de temps réel (SIGALRM sur POSIX) : une expression pathologique n'interrompt que ce document, et l'exécution se termine quand même.

  • AjoutéFonctionneAjouter la classification de la position des liens (tools/link_position.py) :

    navigation, en-tête, barre latérale, pied de page ou contenu, par règles ordonnées sur le chemin des ancêtres d'un lien. Elle réutilise la notion de contenu de content_area.py au lieu d'en inventer une seconde. Branchée sur l'enregistrement des liens de crawl/spider.py derrière link_position.classify (désactivée par défaut, car une position par lien coûte de la mémoire sur un gros crawl), elle est agrégée à l'échelle du site par inlink_composition de crawl/linkgraph.py. Cette agrégation alimente un nouveau constat INLINK_BOILERPLATE_ONLY, pour les pages liées uniquement depuis le gabarit. Le registre passe de 104 à 105 contrôles.

  • AjoutéFonctionneAjouter huit calculs de second passage après le crawl, possibles seulement une fois

    celui-ci terminé (issue #15). Un score de maillage interne calculé à partir du graphe d'arêtes all_inlinks (LOW_LINK_SCORE) ; une cible canonical vers laquelle aucun lien hypertexte ne pointe (UNLINKED_CANONICAL) ; la détection des boucles rel="next" et des séries non liées (PAGINATION_LOOP, UNLINKED_PAGINATION_SERIES) ; la réciprocité hreflang (HREFLANG_MISSING_RETURN_LINK) ; les agrégats de composition des liens entrants (ONLY_NOFOLLOW_INLINKS, ONLY_NONINDEXABLE_SOURCE_INLINKS) ; le chemin de découverte le plus court, concret, depuis le seed du crawl (DEEP_DISCOVERY_PATH) ; un repli calculé en interne pour le contenu mixte (INSECURE_SUBRESOURCE) ; et le regroupement des quasi-doublons à partir du texte de page stocké (NEAR_DUPLICATE / DUPLICATE_BY_HASH), avec le branchement de tools/duplicate.py et tools/content_area.py dans l'audit pour la première fois. ORPHAN_PAGE, SITEMAP_ORPHAN et les deux nouveaux contrôles « non liés » sont désormais retenus : signalés comme un contrôle ignoré nommé, et non comme un constat, sur un crawl que l'agrégateur a marqué comme partiel. « Rien ne pointe vers cette page » ne se prouve pas sur un crawl tronqué. Le registre passe de 104 à 114 contrôles.

  • ModifiéFonctionneAuditer le registre des contrôles du crawl face à une checklist SEO technique externe et

    combler huit lacunes peu coûteuses et vérifiées : cinq contrôles hreflang (codes de langue ou de région invalides, auto-référence absente, x-default manquant, entrées en double, cibles non canoniques), deux directives robots (notranslate, unavailable_after) et les URL canonical contenant un fragment. Le registre passe de 96 à 104 contrôles. Voir docs/CHECKLIST_AUDIT.md.

  • AjoutéFonctionneAjouter asset-weight-check : il récupère les CSS et JS liés à une page et signale les

    ressources bloquant le rendu, les fichiers trop lourds, les bibliothèques en double (par hash de contenu), l'absence de minification, l'absence de font-display, le JS legacy avec polyfills, ainsi que l'absence de compression ou de mise en cache longue durée.

  • AjoutéFonctionneAjouter crawl-site --sitemap <url> (et sitemaps.auto_discover dans --config) :

    amorcer le crawler natif à partir des URL déclarées dans un sitemap, suivre les liens de chacune, puis rapprocher les ensembles déclaré et observé dans le bloc summary.sitemap de audit.json. Le rapprochement utilise les mêmes identifiants de contrôle SITEMAP_ORPHAN / URL_NOT_IN_SITEMAP que ceux déjà remontés par le pipeline Screaming Frog.

  • AjoutéFonctionneAjouter crawl-site --config-help, généré depuis seohead/crawl/config.py, et masquer

    deux options de profondeur et de délai…

    Ajouter crawl-site --config-help, généré depuis seohead/crawl/config.py, et masquer --max-depth et --min-delay dans --help (toujours acceptés), afin que la surface des options cesse de grossir à chaque réglage du crawler.

  • ModifiéFonctionneSéparer la détection des technologies en une étape de récupération et une étape pure

    analyze_tech, capturer les identifiants analytics et des gestionnaires de balises au lieu des seuls noms, et ajouter un rapport tag_coverage qui regroupe la présence par gabarit d'URL et indique comment chaque page a été mesurée.

  • ModifiéFonctionneRésoudre les chaînes et boucles de redirections en second passage sur les cibles de

    redirection d'un crawl terminé…

    Résoudre les chaînes et boucles de redirections en second passage, sur les cibles de redirection propres à un crawl terminé. REDIRECT_CHAIN/REDIRECT_LOOP n'exigent plus le rapport natif Screaming Frog Redirect Chains : un export en profil léger ou une exécution de crawl-site obtient les mêmes constats, sans effort supplémentaire.

  • AjoutéFonctionneAjouter une zone de contenu configurable (content_area.py) qui limite le comptage de

    mots à la zone principale, en excluant par défaut la navigation et le pied de page, sans toucher à la découverte des liens. La stratégie retenue est indiquée pour chaque page.

  • ModifiéFonctionneSéparer les doublons exacts des quasi-doublons dans duplicate.py : les correspondances

    exactes sont hachées à partir du texte extrait (et non des octets bruts) et exclues des groupes de quasi-doublons, et les comparaisons ne portent par défaut que sur les pages indexables.

  • AjoutéFonctionneAjouter un rapport de cohérence des gabarits (boilerplate_report.py) qui hache

    l'en-tête, la navigation et le pied de page de chaque page, et signale les groupes de gabarits minoritaires.

  • AjoutéFonctionneAjouter l'extraction Markdown sans dépendance (markdown_extract.py) : un rendu limité à

    la zone de contenu et un rendu du document complet.

  • ModifiéFonctionneBrancher markdown_extract et boilerplate_report dans la surface CLI et MCP, sous les

    noms markdown-extract / seo_markdown_extract et boilerplate-report / seo_boilerplate_report (47 outils de base, contre 45 auparavant). Ajout du drapeau only_indexable que duplicate_check avait déjà au niveau du handler, à la signature MCP de seo_duplicate_check, où il avait été oublié. citability-check ne lit plus le champ text du parseur sur tout le document (une seule ligne condensée, sans aucune rupture de paragraphe ni de titre) : il s'appuie désormais sur le Markdown de la zone de contenu produit par markdown_extract. Cela corrige à la fois la dilution par le gabarit soulevée dans l'issue et un bug latent où ce texte à plat annulait silencieusement les dimensions Answer-Blocks et Structure-Quality pour toutes les URL en direct. Volontairement non limités : le champ text du parseur lui-même, qui reste sur tout le document, car l'extraction des preuves de schéma de page_facts.py (liens sociaux sameAs, fil d'Ariane, expressions régulières de prix et de notes) dépend de faits qui vivent légitimement dans les widgets d'en-tête et de pied de page, exclus de la zone de contenu ; et les contrôles THIN_CONTENT/LOW_TEXT_RATIO pilotés par Screaming Frog dans sf/core/rules.py, dont word_count et text_ratio proviennent des colonnes d'export de Screaming Frog. Ce sont des données tierces que le toolkit ne peut recadrer sans re-récupérer chaque page, ce qui irait à l'encontre de la conception hors ligne sans requête du chemin d'audit SF. Le crawler du toolkit (crawl-site) bénéficie déjà gratuitement du cadrage sur la zone de contenu, puisque son comptage de mots lit directement parser.parse_html.

  • ModifiéFonctionneRédiger une convention de nommage (docs/NAMING.md) et résoudre les collisions de noms

    de base de modules, ainsi que les fichiers de test nommés d'après un processus, relevés au passage. Aucun nom de commande CLI, de handler ni d'outil MCP n'a changé.

  • AjoutéFonctionneAjouter les fichiers communautaires, de citation et d'onboarding des agents, sans clé

    d'API.

  • AjoutéFonctionneAjouter le skill de workflow analytics-console-review, soumis à autorisation, et trois

    recettes pratiques.

  • ModifiéFonctionneDocumenter la prise en charge de la ligne de sécurité actuelle 3.x.
  • ModifiéFonctionneExiger TLS 1.2 ou plus récent et épingler les sondes de certificat directes aux adresses

    publiques préalablement validées.

  • AjoutéFonctionneAjouter un cache de réponses HTTP pour crawl-site (seohead/crawl/cache.py, activé par

    option…

    Ajouter un cache de réponses HTTP pour crawl-site (seohead/crawl/cache.py, activé via cache.mode, valeur par défaut off, pour qu'aucun effet de bord n'apparaisse derrière un réglage par défaut). Il offre une vraie gestion de la fraîcheur HTTP (max-age / Expires, revalidation ETag / Last-Modified, variantes tenant compte de Vary, respect de no-store / no-cache), un mode replay destiné au débogage, inscrit dans le manifeste et jamais activé par défaut, et un drapeau invalidate pour un rafraîchissement forcé explicite. Chaque page récupérée porte cache_status (hit / revalidated / miss). L'exécution porte cache_stats et cache_replay, à la fois dans la sortie du handler et dans le bloc run de audit.json, si bien qu'un rapport construit en partie depuis le cache le signale. Un hit de cache ne coûte aucune requête et ne consomme ni délai de throttle ni emplacement de la file de dispatch concurrente : l'attente est déclenchée depuis fetch_one lui-même, uniquement lorsqu'un aller-retour réseau réel est sur le point d'avoir lieu.

  • AjoutéFonctionneAjouter la réutilisation pilotée par le journal à seohead/core/runlog.py

    (SEOHEAD_REUSE_POLICY, un âge maximal en secondes par outil ; vide par défaut, ce qui signifie que rien n'est jamais réutilisé). Une réponse antérieure réussie et encore fraîche est renvoyée au lieu de rappeler l'outil. Elle est marquée reused: true avec reused_from_ts, à la fois dans le résultat et dans la nouvelle entrée de journal qui est toujours écrite. La fraîcheur se mesure toujours à partir du moment où la valeur a réellement été récupérée, et la réutilisation ne la prolonge jamais.

Version

3.0.0

Première version publique30 août 2026
10 entrées · Première version publique10 modifié

30 août 2026

10 modifié
  • ModifiéFonctionneUn seul paquet Python avec 42 outils CLI/MCP partagés.
  • ModifiéFonctionneCinq outils MCP Screaming Frog supplémentaires et un analyseur de crawl à 96 contrôles.
  • ModifiéFonctionneReconnaissance du domaine, du CDN, des technologies, de la sécurité, des miroirs, des

    régions, des bots et des backlinks.

  • ModifiéFonctionneValidation Schema.org et génération de graphes connectés.
  • ModifiéFonctionnePreuves de site bornées à partir du sitemap, et rapports XLSX, DOCX, CSV, Markdown et

    JSON.

  • ModifiéFonctionneIntégrations optionnelles Wordstat, SERP Yandex, Arsenkin, Metrika et DataForSEO.
  • ModifiéFonctionneVingt et un skills de workflow techniques et sept playbooks SEO empaquetés.
  • ModifiéFonctionneMCP stdio local et prise en charge de Docker ; ni interface graphique, ni API hébergée,

    ni télémétrie.

  • ModifiéFonctionneREADME public fondé sur des preuves, avec des visuels reproductibles d'audit, de tâches,

    d'interface et de rapports…

    README public fondé sur des preuves, avec des visuels reproductibles (audit synthétique, tâches, interface et rapports).

  • ModifiéFonctionneFrontière de publication sans historique et notices explicites des tiers.

Date = le jour où le changement a atterri (date git de son fragment changelog.d/). Numéro = l'issue qu'il clôture. Titre = première phrase, détails au clic.