Dinoer

Choix techniques

Sept décisions qui façonnent Dinoer, chacune avec sa raison et son coût, dont la règle imposée par une fuite réelle le 14 août 2026.

Chaque choix ci-dessous a une raison et un coût. Les deux sont donnés.

Du texte, jamais des pixels

Diwall, dont Dinoer est issu, se rabat sur un modèle de vision pour les éléments qui n’ont pas de représentation textuelle. Dinoer a retiré cette couche lors de sa reconstruction : captures d’écran, Set-of-Mark, modèle de vision. Aucune option ne la rétablit.

Le coût. Un canvas cliquable ou une image sans libellé accessible est hors de portée. Dinoer vise du texte public à lire et à résumer ; garder un modèle de vision aurait obligé à en faire tourner un en local, ou à envoyer des pages à un modèle hébergé, pour des pages qu’il ne vise pas.

Un navigateur seulement quand la page l’exige

campagne.py lit la plupart des pages avec requests et BeautifulSoup : ni navigateur ni JavaScript. Une page ne passe au cœur de navigation (rpa.py/shot.py) que si la collecte légère la marque insuffisante_legere : une page construite par JavaScript, sans rien de lisible dans son HTML.

Le coût. L’escalade se déclenche sur un texte vide, pas sur un texte inutilisable. Sur une campagne réelle, un profil sur une plateforme d’hébergement de code et une chaîne vidéo ont renvoyé pour tout texte un bandeau de cookies, et ne sont jamais passés au navigateur. Le cas →

Un processus par appel, pas un serveur

Dinoer est une commande, pas un service. shot.py et rpa.py démarrent un navigateur Playwright, font ce que dit le scénario, répondent une fois et se terminent : rien n’écoute sur un port entre deux appels. Chaque appel écrit une entrée dans le journal des opérations, succès ou échec, et passe par le verrou du guide : sans --guide-version valide, et sans le marqueur que laisse un numéro accepté auparavant, il est refusé.

campagne.py fonctionne autrement : un seul processus exécute tout le manifeste, appelle directement sa collecte légère, lance rpa.py comme sous-processus pour les pages qui demandent un navigateur, puis se termine. D’une étape à l’autre, il ne garde que des fichiers : le corpus, le journal des opérations, le cache de recherche.

Le coût. L’état vivant d’une page ne survit pas entre deux appels. Les cookies et le stockage local peuvent être enregistrés puis repris (--sauver-session, --reprendre-session) ; une boîte de dialogue ouverte, un formulaire à moitié rempli ou une position de défilement, non. Une séquence qui dépend de cet état doit tenir en un seul scénario, dans un seul processus. La recette →

Ce que ce choix ne change pas. Un secret est résolu dans le processus Playwright, quel que soit ce qui l’a lancé. Et un modèle hébergé qui lit une sortie en reçoit le contenu, quel que soit le moyen qui l’a transportée.

Une collecte locale, un rapport écrit ailleurs

La collecte tourne là où tourne Dinoer : les requêtes vers SearXNG (local ou distant, à votre choix), la collecte légère, le cœur de navigation. Pas le rapport : il est rédigé par le modèle que vous désignez pour OpenCode dans DINOER_OPENCODE_MODEL, soit un modèle hébergé, soit un modèle Ollama local déclaré à OpenCode. Il n’y a pas de modèle par défaut. Le texte collecté part vers ce modèle.

Le coût. La chaîne n’est pas locale de bout en bout, sauf si vous choisissez un modèle local. Pour une source sensible, choisissez le modèle avant d’y envoyer Dinoer, et lisez lib/modeles.py.

Le modèle qui rédige le rapport reste à l’écart du web

Chaque opencode run que lance Dinoer porte websearch et webfetch à deny dans OPENCODE_CONFIG_CONTENT, quel que soit le répertoire. La règle existe parce que, le 14 août 2026, une campagne a surpris le modèle en train de lancer douze recherches web pendant la rédaction, visibles seulement dans l’enregistrement complet de ses événements.

Le coût. bash reste autorisé, pour les scénarios qui envoient une notification avec curl, et un modèle privé de websearch a atteint le web par bash curl lors d’un essai. L’ouverture est réduite, pas fermée. Détails →

Des signaux, jamais des verdicts

etat.pret_a_agir: false signifie que quelque chose a été remarqué (une signature de pare-feu applicatif, une dérive de session), pas que Dinoer refuse de travailler. La détection de WAF repose sur des mots-clés et peut se tromper ; c’est un compte, jamais une erreur qui interrompt l’exécution.

Le coût. Il faut lire la réponse. Un appelant qui ne regarde que succes ne tire rien de ces signaux.

Le verrou qui fait échouer votre premier appel

Dinoer refuse de s’exécuter tant que celui qui le pilote n’a pas lu le guide et ne peut pas en citer le numéro de version.

Dinoer ne figure dans les données d’entraînement d’aucun modèle, et un modèle qui n’a pas lu le guide invente des commandes et manipule les identifiants dans le shell. Les deux règles par lesquelles commence le guide →

Le coût. Votre premier appel échoue, volontairement, avec {"succes": false, "erreur": "guide_non_lu"}, et chaque commande documentée porte --guide-version.

Le guide n’est jamais traduit. Une traduction pourrait prendre du retard sur l’original pendant que son numéro de version serait mis à jour mécaniquement ; un agent passerait alors le verrou après avoir lu des consignes périmées. Le guide n’existe qu’en anglais.

En bref

  • Aucune vision, et aucune option pour la rétablir.
  • Un navigateur seulement quand la collecte légère ne peut pas lire une page.
  • Un processus par appel : une séquence qui dépend de l’état vivant de la page tient en un scénario.
  • La collecte est locale ; le rapport est rédigé par le modèle que vous choisissez.
  • Le modèle qui rédige le rapport est tenu à l’écart du web, sauf par bash.
  • Des signaux, pas des verdicts : lisez toute la réponse.
  • Le premier appel échoue volontairement, et le guide qui le débloque reste en anglais.