Que fait wiki-lint ?
Avant la première exécution, lisez
docs/GOTCHAS.mddans le kit (faux positifs connus, notes d'exploitation).
Un scan de santé en lecture seule du wiki (wiki_root dans wiki.config.json) ainsi que trois outils de réparation. Tout est basé sur la bibliothèque standard Python et fonctionne à l'identique sur Windows, macOS et Linux. Toutes les règles spécifiques au wiki (dossiers, taxonomie des statuts, plan de champs, exemptions, liste de verbes, motifs de substitution, seuils) sont définies dans la configuration, de sorte que la logique ne change pas lorsque le wiki acquiert un nouveau champ, dossier ou vérification. Conçu pour rester rapide au-delà de 3 000 notes (une exécution complète prend quelques secondes, sauf la vérification 13 qui prend environ une demi-minute à cette échelle).
Compétences connexes
wiki-ingest,wiki-ingest-book: écrivent les notes que cette compétence vérifie (même configuration pour les décisions de statut et le routage d'index).wiki-synthesize: la vérification 15 produit sa liste de travail ; la vérification 32 audite ses sceaux.vocabulary-update: le correctif pour la vérification 30.
Structure
skills/wiki-lint/
SKILL.md
scripts/
lint.py # exécute les vérifications (--only, --out-dir, --self-test)
fix.py # outils de réparation : proposition d'index, rétroliens de la vérification 12, promotion des brouillons
references/
check-origins.md # POURQUOI chaque vérification existe (autorité unique)
cli-reference.md # drapeaux, clés de configuration, fichiers de sortie, structure du rapport
wikikit/lint/ # l'implémentation : context.py, checks_*.py, fixes.py, defaults.json
tests/fixtures/lint/ # mini-wiki synthétique exerçant chaque vérification + expected_counters.txt
Où vit chaque type d'information (ne jamais dupliquer entre ces emplacements) : references/check-origins.md = pourquoi une vérification existe ; ce fichier = ce qu'elle fait ; wikikit/lint/checks_*.py = comment elle est implémentée ; tests/fixtures/lint/expected_counters.txt = pourquoi la valeur de la fixture est ce qu'elle est. À la fin d'une exécution en conditions réelles, l'outil affiche le pointeur check-origins.md pour chaque vérification déclenchée, de sorte que la raison arrive au moment où vous décidez si un résultat est réel ou du bruit.
Invariants d'ingénierie (ne pas casser)
- Toutes les E/S fichier passent par
wikikit.textio(UTF-8 au niveau octet, pas de BOM, retours à la ligne jamais traduits). N'utilisez jamaisopen()en mode texte avec le traitement de nouvelles lignes par défaut : lire et réécrire un fichier CRLF de cette façon le convertit silencieusement. - N'utilisez jamais une expression régulière multiligne avec
$sur du texte pouvant contenir du CRLF :$se place entre le CR et le LF et divise la paire. Éditez par lignes (frontmatter.set_key,fixes._insert_backlinks). - La configuration est la source unique de vérité. Lorsque le wiki gagne un champ, un dossier, un statut ou une exemption, modifiez
wiki.config.json(sectionlint), pas le code. Les valeurs par défaut se trouvent danswikikit/lint/defaults.json. - L'exemption de brouillon est uniforme.
lint.stub_exempt_checksliste les numéros de vérification qui ignorent les notes avecstatus: stub; lisez la liste depuis la configuration, ne la répétez jamais en prose. Les vérifications 10 et 11 excluent les brouillons en ligne (décomptes du système de fichiers). - La détection des espaces réservés est conditionnée à la non-résolution. Un lien wiki dont la cible se résout dans l'index du coffre n'est JAMAIS signalé comme espace réservé, même si son nom correspond à un motif ; les notes d'abréviations légitimes en MAJUSCULES ne doivent pas être signalées.
- Auto-test avant de publier des modifications de logique. Toute modification d'une vérification (nouvelle vérification, seuil modifié, heuristique remaniée) doit passer le test vert :
python skills/wiki-lint/scripts/lint.py --self-test. Mettez à jourtests/fixtures/lint/etexpected_counters.txtensemble lorsque le changement est intentionnel. Prouvez que la fixture discrimine : annulez la modification de logique, relancez et confirmez que le compteur bouge. Une fixture qui réussit à la fois avant et après ne protège rien. - Un zéro est une mesure du détecteur, pas du wiki. Avant de faire confiance au zéro d'une nouvelle vérification, injectez un cas positif et voyez-le se déclencher.
- La propriété du marqueur d'avertissement est positionnelle, jamais basée sur une chaîne d'expressions régulières (vérification 22). Le wiki peut utiliser à la fois
[[Paper]]⚠et⚠[[Paper]]. Le propriétaire d'un glyphe est le lien immédiatement à sa GAUCHE si le texte coupé à gauche se termine par]], sinon le lien à sa DROITE ; un glyphe adjacent à aucun lien est une mise en garde dans le texte courant. Ne résolvez pas cela avec deux expressions régulières chaînées (la deuxième mange le marqueur du lien voisin et désactive silencieusement un drapeau pour une source non vérifiée). Toute édition en masse de marqueurs nécessite un recensement par clef de citation avant et après.
Fonctionnement des vérifications
| # | Nom | Ce qu'il signale | Exemption |
|---|---|---|---|
| 1 | Concepts orphelins | Aucun rétrolien depuis un article/livre (lien en ligne ou concepts_touched) ET aucun d'un concept frère (en ligne ou related_concepts) ; la branche frère empêche les hubs de synthèse de déclencher un faux positif | brouillon |
| 2 | Méthodes orphelines | Aucun rétrolien depuis un article/livre ET aucun lien sortant vers un article/livre | brouillon |
| 3 | concepts_touched vide | Une note d'article avec le champ nul, vide ou [] (également le canari pour la corruption du frontmatter lors des importations par lot) | brouillon |
| 4 | Affirmations non sourcées | Notes de concept avec au moins unsourced_threshold lignes portant un verbe de revendication (verb_list) et aucun lien wiki dans un rayon de +/-unsourced_radius lignes ni sous un titre lié par wiki | brouillon |
| 5 | Liens wiki cassés / espaces réservés | Cible absente de l'index de tout le coffre (cassé), ou correspondant à placeholder_wikilink_patterns lorsqu'elle ne résout pas (espace réservé), ou vide ([[]], cible-vide) | link_target_ignore_patterns (embeds Bases) |
| 6 | Brouillons | promouvoir : un brouillon citant au moins min_distinct_sources_for_final sources DISTINCTES (un livre et ses chapitres comptent pour une œuvre). obsolète : un brouillon plus vieux que stale_days en dessous de ce seuil, ou sans date | aucun |
| 7 | Couverture de l'index | Une note dont le nom de base n'est pas un lien wiki dans index.md | brouillon ; ignoré quand index_mode est bases |
| 7a | Déplacement de section d'index | Un - [[X]] sous la mauvaise section ## (index_sections) | ignoré en mode bases |
| 8 | Synchronisation des book:chapters_ingested | L'ensemble déclaré diffère des fichiers {book}_ChNN.md sur le disque | chapitres brouillons |
| 9 | Chapitre sans book: | Une note *_ChNN dont le lien book: est manquant ou ne résout pas | aucun |
| 10 | Dérive de Quick Stats | Un nombre déclaré dans ## Quick Stats diffère du nombre réel de fichiers dans le dossier mappé (quick_stats_labels) | aucun |
| 11 | Dérive de Couverture par domaine | Les colonnes Concepts/Méthodes de ## Coverage by Field diffèrent des comptes réels non-brouillons (lignes de domaine par field:, lignes de sous-domaine -> par subfield: basées sur le lien [[MOC_*]] ; un sous-domaine avec des notes et sans ligne est MISSING-ROW) | brouillons ; les notes sans domaine sont INFO |
| 12 | concepts_touched bidirectionnel | article -> concepts_touched[token] dont la cible manque du rétrolien [[article]] (asymétrie, auto-corrigeable) ou résout en aucune note (cible-manquante, trier le token) | aucun |
| 13 | Alias sans lien | Un alias documenté (acronyme distinctif ou phrase multi-mots) utilisé dans la prose d'un autre concept/méthode sans lien vers sa note canonique. INFO | brouillon ; alias_link_stoplist ; les blockquotes ne sont pas recherchés |
| 14 | Radar de langue | Un titre (H2-H6) dans une langue autre que celle du wiki, ou au moins prose_threshold hits de mots vides dans la prose. Rapport uniquement ; désactivé sauf si language_radar.enabled | brouillon |
| 15 | Radar de synthèse | Sur les concepts/méthodes final : manquant = qualifié pour un bloc État-des-Connaissances et n'en a aucun ; obsolète = bloc plus vieux que le last_verified le plus récent de ses œuvres citées | non-final |
| 16 | Vocabulaire des statuts | status pas dans status_by_type[type], status ou type manquants, ou fuite de modèle (draft | final) | aucun |
| 17 | Pas de source_verification | Un article sans sceau ; une valeur commençant par abstract n'est PAS un sceau. INFO backlog | brouillon |
| 18 | Vérifié mais incomplet | Un article scellé sans volume ou pages et sans exemption datée check18_exempt: "YYYY-MM-DD, reason" ; les articles de conférence et les thèses sont exemptés par type et forme | brouillon |
| 19 | evidence_level hors vocabulaire | Valeur pas dans evidence_level_vocab (articles seulement) | aucun |
| 20 | ]] dans des citations utiles | Un blockquote sous ## Useful Quotes avec un ]] qui a fui | aucun |
| 21 | Cohorte pré-texte intégral | Un article daté avant synthesis.prefulltext_cutoff sans sceau de texte intégral. INFO | brouillon |
| 22 | Marqueur pré-texte intégral obsolète | Un ⚠ dont le lien wiki propriétaire est un article qui a déjà un sceau de texte intégral, après trois exemptions de queue (mise en garde dans la prose, annotation italique datée, confiance (N src). A de vrais faux positifs | aucun |
| 23 | Espace réservé d'affirmation non rempli | Une ligne correspondant à unfilled_claim_patterns (une source nommée mais aucune affirmation écrite) | aucun |
| 24 | Clé de frontmatter obsolète | Une clé dans deprecated_frontmatter_keys (par défaut journal vers venue) ; correspondance exacte, donc pas de faux positifs | aucun |
| 25 | Figure non citée | Une figure statistique (numeric_claim_patterns) sans lien wiki dans le rayon, classée citée / bloc / méthodes / domaine. INFO. Rien n'est exempté | brouillon ; blockquotes ignorés |
| 26 | Mésappariement de colonnes de tableau | Un tableau dont les lignes ont un nombre de cellules différent de la ligne de délimitation (la seule vérification structurelle) | aucun |
| 27 | Mojibake | Une ligne qui, après un round-trip via encode('cp1252').decode('utf-8'), devient une chaîne différente | aucun |
| 28 | Sceau sans last_verified | Un article/livre avec source_verification et sans last_verified (invisible pour la vérification 15 obsolète). INFO | aucun |
| 29 | Lien slug hors coffre | Un lien wiki vers un slug dans memory_slug_prefixes, à l'échelle du coffre. Désactivé sauf si la liste est non vide | memory_slug_exempt_files |
| 30 | Synchronisation du vocabulaire | _VOCABULARY.md manque un concept/méthode existant (manquant) ou contient une ligne pour une note qui n'existe plus (fantôme). INFO ; correctif /vocabulary-update | aucun |
| 31 | Sceau sans texte | Un sceau d'au plus 60 caractères sans texte de vérification descriptif dans aucun canal. INFO | aucun |
| 32 | Paire sans sceau | Une paire (note, œuvre citée dans son bloc État-des-Connaissances) dont le sceau de la note source ne nomme pas la note. Bloquant ; les dettes déclarées dans seal_debt_file sont signalées mais non comptées | dette déclarée |
| 33 | Pas de titre ou de revue | Un article avec un title ou venue vide | brouillon |
Invocation
Depuis le coffre (le wiki.config.json le plus proche en remontant est la configuration) :
python skills/wiki-lint/scripts/lint.py # toutes les vérifications ; les listes vont dans _temp/
python skills/wiki-lint/scripts/lint.py --only 5,12 # vérifications sélectionnées
python skills/wiki-lint/scripts/lint.py --self-test # fixtures vs expected_counters.txt
python skills/wiki-lint/scripts/fix.py check12 --dry-run
python skills/wiki-lint/scripts/fix.py promote _temp/promote_batch.txt
python skills/wiki-lint/scripts/fix.py index # nécessite index_mode "manual" et une exécution préalable de lint
Drapeaux, clés de configuration et fichiers écrits par chaque vérification : references/cli-reference.md.
Quand modifier quoi
- Nouveau dossier wiki (par exemple
datasets/) : ajoutez-le àfoldersdanswiki.config.json. Il doit être enregistré AVANT la création de notes, sinon chaque lien vers lui sera considéré comme cassé. - Nouvelle valeur de statut : ajoutez-la à
lint.status_by_type.{type}. Nouveau type de note : ajoutez le type avec ses statuts autorisés. - Nouveau champ pour concepts/méthodes : ajoutez le slug à
field_titlecase_map. - Affiner la vérification 4 :
lint.verb_list. Assouplir/resserrer sa tolérance :lint.defaults.unsourced_radius. - Nouveau motif d'espace réservé :
lint.placeholder_wikilink_patterns(rappelez-vous qu'il ne s'applique qu'aux cibles non résolvantes). - Une vérification doit ignorer les brouillons : ajoutez son numéro à
lint.stub_exempt_checks. - Activer le radar de langue : copiez
examples/languages/es.json(ou écrivez vos propres listes) danslint.language_radar. - Ajouter une nouvelle vérification : implémentez-la dans
wikikit/lint/checks_*.py, ajoutez ses compteurs àexpected_counters.txt, ajoutez une fixture qui l'exerce, écrivez son entrée dansreferences/check-origins.md. Une vérification dont le motif n'est pas écrit sera désactivée la première fois qu'elle semblera bruyante. Si le motif ne peut pas être sourcé, écrivez "non documenté" ; n'en inventez jamais.
Règles de sécurité
- Le lint est en lecture seule vis-à-vis du wiki ; il écrit seulement les listes par vérification dans
--out-dir(par défaut_temp/). fix.pyne modifie les notes que là où il le signale (rétroliens, statut), conserve les fins de ligne de chaque fichier et journalise tout changement pour annulation.- En cas de doute sur la justesse d'une modification d'heuristique, écrivez d'abord la fixture, regardez l'auto-test échouer, puis effectuez la modification.
- Les répertoires de cache ne sont jamais versionnés (
_temp/et autres restent dans.gitignore). Une mesure versionnée sera lue des mois plus tard comme si elle datait d'aujourd'hui.