Dinoer

Choix techniques

Sept décisions qui façonnent Dinoer, chacune avec la raison qui la sous-tend et le prix qu'elle entraîne. Y compris celle qui a été imposée par une véritable fuite, le même jour où elle a été découverte.

Chaque option ci-dessous a un coût. Énumérer les avantages sans indiquer le prix transformerait cette page en une publicité plutôt qu’en un document que vous pouvez évaluer.

Texte superposé aux pixels, sans rien de gardé en réserve

Diwall, l’outil à partir duquel Dinoer a été développé, considère la vision comme une solution de secours pour les éléments qui ne possèdent pas de représentation sémantique. Dinoer ne conserve pas cette solution de secours : toute la couche de perception — captures d’écran, Set-of-Mark, le modèle de vision — a été supprimée lors d’une reconstruction complète, et n’a pas été rendue optionnelle. Il n’existe aucun paramètre qui permette de la réactiver.

Le prix. Une zone cliquable ou une image sans étiquette accessible est en dehors de ce sur quoi Dinoer peut agir, point final. L’outil dont Dinoer est dérivé pourrait toujours revenir à un modèle de vision. Ce choix a été fait intentionnellement : les tâches que Dinoer vise — la lecture et la synthèse de textes publics — n’ont jamais eu besoin de cela, et inclure cette capacité aurait entraîné son coût (un modèle local à exécuter, un modèle distant dont il faut faire attention) pour une catégorie de pages que ce projet ne cible pas.

N’escaladez qu’en cas de réel besoin pour une page

campagne.py lit la plupart des pages avec requests + BeautifulSoup — sans navigateur, sans JavaScript, pour une fraction du coût d’une session Playwright complète. Une page ne bascule vers le cœur du navigateur conservé (rpa.py/shot.py) que lorsque le palier léger la marque insuffisante_legere — une coquille rendue en JS sans rien de lisible dans le HTML brut.

Le prix. Le déclencheur d’escalade est actuellement basé sur « texte vide », et non sur « texte présent mais inutilisable ». Une campagne réelle a identifié deux pages—un profil GitHub, une chaîne YouTube—qui renvoyaient du texte et n’ont donc jamais fait l’objet d’une escalade, et ce texte était simplement du bruit provenant de bannières publicitaires, sans autre contenu. Il s’agit d’une lacune réelle dans l’architecture, et non d’un problème caché. L’intégralité du cas →

Un processus par appel, pas un serveur

Dinoer est une commande, et non un service. shot.py et rpa.py démarrent un processus Playwright, exécutent les actions décrites dans le scénario, répondent une seule fois et se terminent : aucun script du produit n’écoute sur un port entre deux appels. Chaque appel écrit une entrée dans le journal des opérations, indiquant le succès ou l’échec, et chaque appel rencontre le verrou de lecture du guide — sans jeton --guide-version valide ni marqueur local, il est refusé.

campagne.py a une autre forme : un processus qui exécute tout un manifeste, appelant sa collecte légère dans le même processus et rpa.py en sous-processus pour les pages qui nécessitent un navigateur, puis se termine. Ce qu’il conserve d’une étape à l’autre est des fichiers : le corpus, le journal des opérations et le cache de recherche.

Le prix. L’état vivant de la page ne persiste pas entre deux appels. Les cookies et le stockage local peuvent être sauvegardés et restaurés (--sauver-session, --reprendre-session); une fenêtre modale ouverte, un formulaire à moitié rempli ou une position de défilement ne le peuvent pas. Une séquence qui dépend de cet état doit être un seul scénario, dans un seul processus — la recette pour les sessions perdues montre ce que cela donne quand ce n’est pas le cas.

Ce que ce choix ne modifie pas. Le transport ne décide pas où un secret est résolu : cela se fait à l’intérieur du processus Playwright, quel que soit ce qui l’a lancé. Un protocole ne décide de rien ; c’est l’agent qui pilote l’outil qui décide. Et un modèle hébergé qui lit une sortie la reçoit, quel que soit le moyen par lequel elle y est acheminée.

Collecte locale, une synthèse déléguée que vous devez choisir avec soin

Collection reste sur votre machine : SearXNG (local ou distant, vous choisissez), requests, et le cœur du navigateur conservé fonctionnent tous là où Dinoer fonctionne. La synthèse de rapports ne se fait pas localement ; elle est déléguée à OpenCode ou à un modèle Ollama local, et les modèles gratuits d’OpenCode sont le moteur de raisonnement par défaut. Le texte des pages collectées peut être transmis au serveur que vous configurez.

Le prix. Ce n’est pas une garantie locale pour l’ensemble du pipeline, et cette page ne prétend pas l’être. Si une source est sensible, consultez lib/modeles.py et choisissez le back-end délibérément avant de diriger Dinoer vers elle — la même discipline opencode.jsonc qui s’applique à l’accès aux outils s’applique ici à la destination du texte lui-même.

Le corpus est ce que le modèle est censé ne pas modifier — et pourtant, il l’a modifié, une fois

opencode.jsonc, local au projet, refuse au modèle délégué ses propres websearch / webfetch outils — et depuis la 1.0.1 le même refus voyage dans OPENCODE_CONFIG_CONTENT à chaque opencode run que Dinoer lance, quel que soit le répertoire. Il existe parce qu’en date du 14 août 2026, une véritable campagne a surpris le modèle en train de faire exactement ce qu’il nie maintenant : douze recherches web en direct, trouvant du contenu absent du corpus collecté, invisible dans la réponse finale et détectable uniquement en capturant tout le flux d’événements plutôt qu’en se fiant au texte renvoyé.

Le prix est indiqué clairement, plutôt que caché. bash reste autorisé — certains scénarios nécessitent réellement cela, pour curl une notification — et un modèle qui a été refusé websearch a, lors d’une véritable exécution de vérification, atteint le web en direct via bash curl. Ce n’est pas une garantie absolue. Une surface réduite, et la manière honnête de le décrire à un opérateur est exactement cette phrase, et non “contenu”.

Signaux, jamais des jugements

Dinoer rapporte ce qu’il a remarqué et vous laisse décider. etat.pret_a_agir: false signifie « une friction a été perçue » — une signature WAF, un décalage de session — et non « un refus de fonctionner ». La détection WAF est basée sur des mots-clés et peut être erronée ; elle est présentée sous forme de nombre, et jamais comme une exception qui interrompt une exécution.

Le prix. Vous devez lire la réponse. Un appel qui ne regarde que succes n’en tire aucun avantage.

Le blocage qui fait échouer votre première tentative

Dinoer refuse de s’exécuter tant que la personne qui le pilote n’a pas lu le guide et ne peut citer sa version.

Dinoer ne figure dans les données d’entraînement de aucun modèle, et un modèle qui n’a pas lu le guide improvise. Ce n’est pas hypothétique ; cela a causé une violation de sécurité documentée dans le projet prédécésent, et ce verrou est la solution. Ce à quoi ressemble l’improvisation, et les deux règles qui l’empêchent →

Le prix. Votre premier appel échoue délibérément, avec {"succes": false, "erreur": "guide_non_lu"}. Chaque commande documentée contient --guide-version. C’est une friction, c’est intentionnel.

Et cela n’est jamais traduit. Le guide existe uniquement en anglais. Un guide traduit peut entraîner une désynchronisation silencieuse : son numéro de version est resynchronisé mécaniquement alors que son contenu décrit toujours la version précédente, et un agent passe alors le verrou après avoir lu des instructions obsolètes. Un modèle lit l’anglais nativement et l’anglais coûte moins de tokens : l’avantage de le traduire est nul, le risque est réel.

En bref

  • Pas de solution de repli pour l’affichage, intentionnellement — ni une version réduite de celle de Diwall, mais une absence totale.
  • L’affichage passe au navigateur uniquement lorsque le niveau le plus bas ne peut pas lire une page.
  • Un processus par appel, pas un serveur — donc, une séquence qui nécessite l’état actuel de la page est un scénario possible.
  • La collecte est locale ; la synthèse est déléguée — vérifiez le back-end avant une source sensible.
  • La limite du corpus est appliquée, et non simplement supposée — et son véritable écart est publié, et non adouci.
  • Des signaux plutôt que des verdicts — vous décidez, vous devez donc lire.
  • La première exécution échoue intentionnellement, et le guide qui la débloque n’est jamais traduit.