diff --git a/.opencode/.gitignore b/.opencode/.gitignore new file mode 100644 index 0000000..67041b2 --- /dev/null +++ b/.opencode/.gitignore @@ -0,0 +1,5 @@ +node_modules +package.json +package-lock.json +bun.lock +work/ diff --git a/.opencode/agents/lardon-architect.md b/.opencode/agents/lardon-architect.md index 02b1607..f6412b1 100644 --- a/.opencode/agents/lardon-architect.md +++ b/.opencode/agents/lardon-architect.md @@ -9,6 +9,7 @@ permission: task: deny --- -Analyse uniquement. Vérifie les frontières TUI, métier, scheduler et gouverneur, +Interviens uniquement pour une API publique, le scheduler, le gouverneur, le +DAG, la persistance ou une concurrence importante. Vérifie les frontières, les propriétés, durées de vie et invariants documentés. Ne modifie aucun fichier -et rends au parent un rapport concis, avec les défauts bloquants en premier. +et rends au parent seulement conclusions, risques, fichiers et décisions. diff --git a/.opencode/agents/lardon-build-backup.md b/.opencode/agents/lardon-build-backup.md new file mode 100644 index 0000000..1ef9a56 --- /dev/null +++ b/.opencode/agents/lardon-build-backup.md @@ -0,0 +1,16 @@ +--- +description: Reprend les tickets complexes interrompus sans refaire l'analyse +mode: subagent +model: opencode/nemotron-3-ultra-free +temperature: 0.1 +permission: + edit: + "*": allow + "scan3d/**": deny + task: deny +--- + +Lis d'abord `.opencode/work/current_ticket.md`, le diff et les seuls fichiers +concernés. Reprends le working tree existant à la prochaine action sûre sans +refaire l'analyse si le handoff suffit. Implémente minimalement, sans sous-agent, +commit, push ni modèle payant. Mets à jour le handoff avec un résumé concis. diff --git a/.opencode/agents/lardon-build-light.md b/.opencode/agents/lardon-build-light.md new file mode 100644 index 0000000..21636da --- /dev/null +++ b/.opencode/agents/lardon-build-light.md @@ -0,0 +1,17 @@ +--- +description: Traite les petits tickets et corrections locales à faible coût +mode: subagent +model: opencode/mimo-v2.5-free +temperature: 0.1 +permission: + edit: + "*": allow + "scan3d/**": deny + task: deny +--- + +Traite seulement les petits changements locaux, tests simples, nettoyage ou +documentation demandée. Lis le handoff et les fichiers ciblés, sans sous-agent. +Si le ticket touche une fondation sensible, une API complexe ou exige un gros +refactoring, arrête-toi et signale qu'il faut Nemotron, DeepSeek ou Codex. Ne +réécris jamais une fondation pour contourner cette limite. diff --git a/.opencode/agents/lardon-build.md b/.opencode/agents/lardon-build.md index ba772ef..d7bfbb9 100644 --- a/.opencode/agents/lardon-build.md +++ b/.opencode/agents/lardon-build.md @@ -1,26 +1,18 @@ --- -description: Agent principal C17 qui orchestre et implémente les tickets Lardon3D -mode: primary +description: Implémente seul les tickets complexes Lardon3D +mode: subagent model: opencode/deepseek-v4-flash-free temperature: 0.1 permission: edit: "*": allow "scan3d/**": deny - task: - "*": deny - "lardon-architect": allow - "lardon-explore": allow - "lardon-review": allow - "lardon-concurrency": allow - "lardon-tests": allow - "lardon-docs": allow + task: deny --- -Orchestre le ticket avec le minimum de sous-agents pertinents. Un seul agent -modifie les sources à un instant donné : toi. Lis les instructions projet déjà -chargées, préserve les changements existants et fournis aux sous-agents un -périmètre précis. Leurs rapports doivent rester concis. N'imbrique jamais de -sous-agent. Si DeepSeek retourne une saturation 503, demande à l'utilisateur de -relancer avec `opencode/nemotron-3-ultra-free`; ne sélectionne jamais un modèle -payant. +Implémente uniquement le plan concis transmis par l'orchestrateur. Lis le +handoff et seulement les fichiers et documents indiqués. Ne refais pas +l'exploration, ne lance aucun sous-agent et préserve le working tree existant. +Tu es l'unique auteur des sources pendant ta phase. Mets à jour le handoff avec +les changements et erreurs utiles, sans longs logs. Aucun commit, push ou +modèle payant. diff --git a/.opencode/agents/lardon-concurrency.md b/.opencode/agents/lardon-concurrency.md index 1b32d40..e48c667 100644 --- a/.opencode/agents/lardon-concurrency.md +++ b/.opencode/agents/lardon-concurrency.md @@ -14,5 +14,5 @@ permission: Audite pthread, mutex, conditions, transitions d'état, réveils perdus, deadlocks, doubles libérations et data races. Cet audit est obligatoire pour -task, task_queue et resource_governor. Ne modifie rien et rapporte les scénarios -précis au parent. +task, task_queue et resource_governor, mais inutile hors code concurrent. Ne +modifie rien et rapporte uniquement les scénarios précis et leur gravité. diff --git a/.opencode/agents/lardon-docs.md b/.opencode/agents/lardon-docs.md index 83a0173..419f29b 100644 --- a/.opencode/agents/lardon-docs.md +++ b/.opencode/agents/lardon-docs.md @@ -13,5 +13,6 @@ permission: task: deny --- -Modifie uniquement README.md, AGENTS.md et docs/. Synthétise les documents -chargés sans les dupliquer et ne change jamais le code ou la configuration. +Modifie uniquement README.md, AGENTS.md et docs/ lorsqu'un ticket le demande +explicitement. Charge seulement les documents pertinents, synthétise sans les +dupliquer et ne change jamais le code ou la configuration. diff --git a/.opencode/agents/lardon-explore.md b/.opencode/agents/lardon-explore.md index ecd3398..f7cc049 100644 --- a/.opencode/agents/lardon-explore.md +++ b/.opencode/agents/lardon-explore.md @@ -13,5 +13,6 @@ permission: --- Travaille en lecture seule. Localise exactement les fichiers, symboles, -appelants et dépendances demandés. Ne propose pas de réécriture et retourne des -chemins et conclusions synthétiques au parent. +appelants, dépendances et documents strictement utiles. Ne lis pas toute +l'architecture par défaut, ne propose pas de réécriture et retourne uniquement +les chemins, conclusions et risques synthétiques. diff --git a/.opencode/agents/lardon-orchestrator.md b/.opencode/agents/lardon-orchestrator.md new file mode 100644 index 0000000..21bf1ce --- /dev/null +++ b/.opencode/agents/lardon-orchestrator.md @@ -0,0 +1,32 @@ +--- +description: Orchestre les tickets avec un contexte minimal et sans écrire les sources +mode: primary +model: opencode/north-mini-code-free +temperature: 0.1 +permission: + edit: + "*": deny + ".opencode/work/current_ticket.md": allow + bash: + "*": deny + "git status*": allow + "git diff*": allow + "codex --help*": allow + task: + "*": deny + "lardon-build": allow + "lardon-build-backup": allow + "lardon-build-light": allow + "lardon-architect": allow + "lardon-explore": allow + "lardon-review": allow + "lardon-concurrency": allow + "lardon-tests": allow + "lardon-docs": allow +--- + +Orchestre sans modifier les sources. Charge AGENTS.md et l'overview déjà +injectés, puis utilise explore pour cibler le contexte. N'appelle que les agents +pertinents, sans sous-agent imbriqué. Transmets au seul implémenteur un résumé +court : objectif, contraintes, fichiers, API, invariants et tests. Tiens le +handoff concis à jour après chaque phase. Aucun modèle payant, commit ou push. diff --git a/.opencode/agents/lardon-review.md b/.opencode/agents/lardon-review.md index 9c2fabe..e5b3345 100644 --- a/.opencode/agents/lardon-review.md +++ b/.opencode/agents/lardon-review.md @@ -14,4 +14,4 @@ permission: Relis le diff sans le modifier. Vérifie C17, erreurs, nettoyage, overflows, contrats d'API, ownership et conformité à AGENTS.md. Distingue bloquants, -importants et améliorations, puis rends un rapport court. +importants et limites. Ne répète pas les tests réussis et rends un rapport court. diff --git a/.opencode/agents/lardon-tests.md b/.opencode/agents/lardon-tests.md index 47d5ad9..5fb82cf 100644 --- a/.opencode/agents/lardon-tests.md +++ b/.opencode/agents/lardon-tests.md @@ -17,6 +17,6 @@ permission: --- Exécute les commandes demandées et rapporte leurs sorties réelles. Utilise le -build normal, ASan/UBSan et TSan selon le risque. Ne modifie jamais le code sauf -instruction explicite du prompt principal, auquel cas refuse et renvoie la -correction au seul agent implémenteur. +build normal, ASan/UBSan et TSan selon le risque. Ne modifie jamais le code : si +une correction est nécessaire, renvoie-la au seul agent implémenteur. Pour les +succès, rapporte seulement commande, statut et synthèse. diff --git a/.opencode/commands/lardon-codex-handoff.md b/.opencode/commands/lardon-codex-handoff.md new file mode 100644 index 0000000..97674aa --- /dev/null +++ b/.opencode/commands/lardon-codex-handoff.md @@ -0,0 +1,11 @@ +--- +description: Préparer une reprise courte dans Codex CLI +agent: lardon-orchestrator +subtask: false +--- + +Mets le handoff à jour depuis le statut et le diff, sans modifier les sources. +Vérifie d'abord `codex --help`. Produis ensuite un prompt court copiable qui +demande à Codex de lire AGENTS.md, le handoff, le diff et seulement les fichiers +cités, puis de reprendre à la prochaine action sûre. Ne lance pas Codex, n'invente +aucune option, ne demande aucune clé et n'inclus aucun secret. diff --git a/.opencode/commands/lardon-handoff.md b/.opencode/commands/lardon-handoff.md index f8b05dd..70cb90c 100644 --- a/.opencode/commands/lardon-handoff.md +++ b/.opencode/commands/lardon-handoff.md @@ -1,10 +1,10 @@ --- description: Produire un compte rendu de transmission sans modifier le dépôt -agent: lardon-build +agent: lardon-orchestrator subtask: false --- -Sans modifier le code ni la documentation, produis un compte rendu autonome -pour une autre session ou un autre modèle : objectif, architecture pertinente, -état Git, travail réalisé, validations réellement exécutées, défauts et limites, -fichiers concernés et prochaine action sûre. +Sans modifier le code ni la documentation suivie, lis le handoff, le statut Git +et le diff, puis produis un compte rendu autonome : objectif, contraintes, +architecture strictement pertinente, travail réalisé, validations réelles, +défauts, fichiers et prochaine action sûre. N'inclus aucun long log ni secret. diff --git a/.opencode/commands/lardon-plan.md b/.opencode/commands/lardon-plan.md new file mode 100644 index 0000000..ef9b3de --- /dev/null +++ b/.opencode/commands/lardon-plan.md @@ -0,0 +1,14 @@ +--- +description: Planifier en lecture seule avec un contexte minimal +agent: lardon-orchestrator +subtask: false +--- + +Planifie ce ticket sans modifier les sources : $ARGUMENTS + +Lis AGENTS.md et l'overview déjà chargés. Demande à lardon-explore uniquement +les modules concernés. Liste les fichiers et documents à charger, propose un plan +court et indique les agents réellement nécessaires. Écris dans +`.opencode/work/current_ticket.md` : titre, objectif, contraintes, fichiers, +documents utiles, plan, travail terminé/restant, fichiers modifiés, commandes, +tests passés/restants, décisions, erreurs, modèle et prochaine action sûre. diff --git a/.opencode/commands/lardon-resume-backup.md b/.opencode/commands/lardon-resume-backup.md new file mode 100644 index 0000000..59938ea --- /dev/null +++ b/.opencode/commands/lardon-resume-backup.md @@ -0,0 +1,10 @@ +--- +description: Reprise rapide du handoff avec Nemotron +agent: lardon-orchestrator +subtask: false +--- + +Reprends le ticket avec lardon-build-backup. Lis uniquement le handoff, le diff +et les fichiers qu'ils citent. Ne refais ni exploration ni architecture si les +informations suffisent. Appelle concurrency uniquement si nécessaire, puis mets +le handoff à jour avec la prochaine action sûre. diff --git a/.opencode/commands/lardon-resume-from-codex.md b/.opencode/commands/lardon-resume-from-codex.md new file mode 100644 index 0000000..e4461d3 --- /dev/null +++ b/.opencode/commands/lardon-resume-from-codex.md @@ -0,0 +1,10 @@ +--- +description: Reprendre dans OpenCode le working tree laissé par Codex +agent: lardon-orchestrator +subtask: false +--- + +Lis le handoff et inspecte le diff laissé par Codex. Charge uniquement les +fichiers modifiés, sans refaire l'architecture. Lance lardon-review, puis +lardon-concurrency seulement si pertinent, puis lardon-tests. Mets le handoff à +jour avec les résultats et la prochaine action. Ne modifie pas les sources. diff --git a/.opencode/commands/lardon-resume-light.md b/.opencode/commands/lardon-resume-light.md new file mode 100644 index 0000000..c449156 --- /dev/null +++ b/.opencode/commands/lardon-resume-light.md @@ -0,0 +1,10 @@ +--- +description: Reprise limitée d'un petit ticket avec MiMo +agent: lardon-orchestrator +subtask: false +--- + +Lis le handoff, le diff et les fichiers cités, puis confie uniquement un petit +travail local à lardon-build-light. Si le reste touche une fondation, une API ou +un refactoring sensible, ne modifie rien : conserve le handoff et recommande +DeepSeek, Nemotron ou Codex. Mets à jour la prochaine action sûre. diff --git a/.opencode/commands/lardon-review.md b/.opencode/commands/lardon-review.md index bbf5d93..ed0930c 100644 --- a/.opencode/commands/lardon-review.md +++ b/.opencode/commands/lardon-review.md @@ -1,9 +1,10 @@ --- description: Lancer une revue indépendante sans modification -agent: lardon-build +agent: lardon-orchestrator subtask: false --- -Sans modifier aucun fichier, lance lardon-review et lardon-concurrency comme -sous-tâches indépendantes sur le diff courant. Agrège leurs rapports en -distinguant défauts bloquants, risques et limites. Ne lance aucun autre agent. +Sans modifier aucun fichier, lance lardon-review sur le diff courant. Lance +lardon-concurrency en sous-tâche indépendante uniquement si le diff touche +pthread, task, task_queue ou resource_governor. Agrège seulement les défauts, +risques et limites. Ne lance aucun autre agent. diff --git a/.opencode/commands/lardon-save-handoff.md b/.opencode/commands/lardon-save-handoff.md new file mode 100644 index 0000000..5a247f6 --- /dev/null +++ b/.opencode/commands/lardon-save-handoff.md @@ -0,0 +1,10 @@ +--- +description: Sauvegarder l'état courant du ticket sans modifier les sources +agent: lardon-orchestrator +subtask: false +--- + +Sans sous-agent ni modification des sources, inspecte `git status`, le diff et +le handoff existant. Mets `.opencode/work/current_ticket.md` à jour avec les +rubriques prescrites. Résume les commandes et erreurs ; ne copie ni sources, +documentation, longs logs, secrets ou données utilisateur. diff --git a/.opencode/commands/lardon-small.md b/.opencode/commands/lardon-small.md new file mode 100644 index 0000000..8d23275 --- /dev/null +++ b/.opencode/commands/lardon-small.md @@ -0,0 +1,14 @@ +--- +description: Traiter un petit ticket avec MiMo et des validations ciblées +agent: lardon-orchestrator +subtask: false +--- + +Traite ce petit ticket : $ARGUMENTS + +Utilise lardon-explore pour cibler les fichiers, puis un seul lardon-build-light +pour modifier. N'appelle architect, concurrency ou docs que si leur besoin est +avéré ; si le ticket est sensible, arrête et recommande le workflow normal. +Appelle ensuite lardon-tests pour compilation, tests ciblés et +`git diff --check`, puis une revue seulement si le diff le justifie. Maintiens +le handoff concis. Aucun commit, push ou fallback payant. diff --git a/.opencode/commands/lardon-ticket-backup.md b/.opencode/commands/lardon-ticket-backup.md new file mode 100644 index 0000000..59beb40 --- /dev/null +++ b/.opencode/commands/lardon-ticket-backup.md @@ -0,0 +1,11 @@ +--- +description: Reprendre un ticket gratuit avec Nemotron après indisponibilité DeepSeek +agent: lardon-orchestrator +subtask: false +--- + +Lis d'abord `.opencode/work/current_ticket.md` et le diff. Si le handoff suffit, +ne refais pas l'exploration. Transmets seulement l'objectif, les fichiers, les +invariants, le travail restant et la prochaine action à lardon-build-backup. +Après reprise, appelle lardon-tests puis lardon-review ; concurrency uniquement +si pertinent. Mets à jour le handoff après chaque phase. Aucun modèle payant. diff --git a/.opencode/commands/lardon-ticket.md b/.opencode/commands/lardon-ticket.md index 6325461..74c2bcd 100644 --- a/.opencode/commands/lardon-ticket.md +++ b/.opencode/commands/lardon-ticket.md @@ -1,14 +1,19 @@ --- -description: Traiter un ticket Lardon3D avec exploration, architecture, tests et revue -agent: lardon-build +description: Traiter un ticket gratuit avec contexte progressif et handoff +agent: lardon-orchestrator subtask: false --- Traite ce ticket : $ARGUMENTS -Lis les instructions déjà chargées, inspecte Git et les fichiers concernés. -Utilise lardon-explore puis lardon-architect seulement si pertinents. Après leur -rapport, implémente seul et minimalement. Délègue la validation à lardon-tests, -puis la revue finale à lardon-review et obligatoirement à lardon-concurrency si -task, task_queue, resource_governor ou pthread sont touchés. Aucun sous-agent -imbriqué, commit, push ou ajout de scan3d/. +1. Initialise `.opencode/work/current_ticket.md` avec les rubriques prescrites. +2. Demande à lardon-explore les seuls fichiers et documents utiles. +3. Charge uniquement ce contexte. Appelle lardon-architect seulement pour une + abstraction importante, puis transmets un résumé concis à lardon-build. +4. Après l'implémentation, appelle lardon-tests une fois, puis lardon-review une + fois. Ajoute lardon-concurrency uniquement pour du code concurrent. +5. Mets le handoff à jour après chaque phase avec conclusions, commandes, + erreurs et prochaine action, sans documentation, sources ou logs complets. + +Un seul agent écrit les sources. Aucun sous-agent imbriqué, commit, push, +fallback payant ou modification de scan3d/. diff --git a/.opencode/opencode.json b/.opencode/opencode.json index 6c6d946..3026efb 100644 --- a/.opencode/opencode.json +++ b/.opencode/opencode.json @@ -1,15 +1,11 @@ { "$schema": "https://opencode.ai/config.json", - "default_agent": "lardon-build", - "model": "opencode/deepseek-v4-flash-free", + "default_agent": "lardon-orchestrator", + "model": "opencode/north-mini-code-free", "subagent_depth": 1, "instructions": [ "AGENTS.md", - "docs/architecture/overview.md", - "docs/architecture/resource_governor.md", - "docs/architecture/scheduler_resource_integration.md", - "docs/architecture/foundation_review.md", - "docs/opencode_handoff.md" + "docs/architecture/overview.md" ], "permission": { "*": "ask", @@ -20,7 +16,8 @@ "external_directory": "deny", "edit": { "*": "allow", - "scan3d/**": "deny" + "scan3d/**": "deny", + "scan3d/tri_photos.py": "deny" }, "bash": { "*": "ask", @@ -40,6 +37,7 @@ "ignore": [ ".git/**", "build*/**", + ".opencode/work/**", "scan3d/**" ] } diff --git a/docs/opencode_models.md b/docs/opencode_models.md index 09a7a9e..2f80f57 100644 --- a/docs/opencode_models.md +++ b/docs/opencode_models.md @@ -61,6 +61,63 @@ indisponibles, interrompre le travail plutôt que choisir un modèle payant. Aucun fournisseur ni modèle local n'a été détecté dans la configuration OpenCode actuelle. +## Optimisation du quota + +L'agent par défaut est `lardon-orchestrator` sur North Mini Code Free. Il charge +seulement `AGENTS.md` et l'overview, puis demande à North Mini Code une +exploration ciblée. DeepSeek est réservé à l'implémentation complexe ; il ne sert +ni à l'orchestration, ni aux tests, ni à la documentation. Nemotron traite les +reprises et analyses d'architecture ou de concurrence, MiMo les petits tickets, +Laguna la revue et Ling la documentation. + +Les commandes `lardon-plan`, `lardon-small`, `lardon-ticket` et +`lardon-ticket-backup` chargent progressivement le contexte. Elles ne lisent pas +automatiquement toute l'architecture et transmettent uniquement objectif, +contraintes, fichiers, API, invariants, risques et tests. Les rapports de succès +restent courts. Le handoff ignoré `.opencode/work/current_ticket.md` permet une +reprise sans rejouer toute l'analyse. + +## Chaîne de secours + +La voie normale est DeepSeek V4 Flash Free pour l'implémentation. En cas de 503, +saturation, quota épuisé ou interruption, sauvegarder le handoff et reprendre +avec Nemotron 3 Ultra Free. Si Nemotron est indisponible, MiMo V2.5 Free est +limité aux petits changements ; il doit refuser une fondation sensible. + +GPT-5.6 Sol n'est pas actif dans OpenCode, car l'identifiant visible passe par +Zen et annonce un tarif. Pour utiliser le quota ChatGPT/Codex, la voie normale +reste Codex CLI via `lardon-codex-handoff`, puis +`lardon-resume-from-codex`. Aucun modèle payant n'est un fallback. + +## GPT-5.6 Sol dans OpenCode + +Vérification locale du 6 août 2026 avec OpenCode 1.18.13 : + +- identifiant exact : `opencode/gpt-5.6-sol` ; +- fournisseur : `opencode`, affiché comme OpenCode Zen ; +- endpoint déclaré : `https://opencode.ai/zen/v1` ; +- authentification active : credential Zen de type `api` ; +- clé OpenAI API séparée : non requise par cette route Zen, mais le credential + Zen reste nécessaire ; +- OAuth ChatGPT/Codex : non détecté ; +- plugin Codex OAuth : non installé ; +- OpenCode Zen utilisé : oui ; +- tarif affiché : entrée 5, sortie 30, cache lecture 0,5 et écriture 6,25 dans + les unités tarifaires retournées par OpenCode ; tarifs supérieurs au-delà du + palier de contexte indiqué ; +- facturation distincte du quota Codex : route Zen tarifée, donc à considérer + distincte ; +- quota Codex partagé : non confirmé et aucune preuve locale ne l'indique ; +- test minimal : non exécuté, car la route identifiée est payante ; +- classement : **Q3 — GPT-5.6 Sol fourni par OpenCode Zen** ; +- politique : aucun agent, commande active ou fallback Sol dans OpenCode. + +La preuve locale combine `opencode models --refresh --verbose`, qui expose le +fournisseur, l'endpoint et le coût, et `opencode providers list`, qui expose un +seul credential OpenCode Zen. La configuration globale ne déclare aucun +fournisseur OpenAI ni plugin d'authentification Codex. Aucun secret n'a été lu +ou reproduit dans ce document. + ## Actualisation Les offres changent. Réexécuter : diff --git a/docs/opencode_workflow.md b/docs/opencode_workflow.md new file mode 100644 index 0000000..5c74dd1 --- /dev/null +++ b/docs/opencode_workflow.md @@ -0,0 +1,76 @@ +# Workflow OpenCode et Codex + +Ce workflow minimise le contexte tout en conservant un handoff fiable. Le +fichier `.opencode/work/current_ticket.md` est local et ignoré par Git. Il ne +contient que l'objectif, les contraintes, fichiers et documents utiles, plan, +travail terminé et restant, fichiers modifiés, commandes, tests, décisions, +erreurs, modèle actif et prochaine action sûre. + +## A. Ticket gratuit normal + +Lancer `/lardon-plan`, puis `/lardon-ticket`. North orchestre et explore via des +agents distincts, puis DeepSeek implémente. Architect et concurrency ne sont appelés que si le +périmètre l'exige. Tests et revue interviennent une seule fois après le code. + +## B. DeepSeek retourne 503 + +Lancer `/lardon-save-handoff`, puis `/lardon-resume-backup`. Nemotron lit le +handoff et le diff, reprend la prochaine action et ne refait pas l'analyse si +les informations suffisent. + +## C. DeepSeek et Nemotron sont indisponibles + +Lancer `/lardon-resume-light` uniquement si le travail restant est petit et +local. Pour une fondation sensible, conserver le handoff et attendre DeepSeek +ou Codex ; ne pas forcer MiMo à réécrire l'architecture. + +## D. Petit ticket avec MiMo + +Lancer `/lardon-small`. L'exploration reste ciblée, MiMo est le seul auteur, +puis les validations ciblées et `git diff --check` sont exécutées. Basculer vers +le workflow normal si la complexité dépasse une correction locale. + +## E. Quota Codex renouvelé + +GPT-5.6 Sol visible dans OpenCode est une offre Zen payante, pas une voie Codex +confirmée. Lancer `/lardon-codex-handoff`, copier le prompt court produit dans +Codex CLI, puis utiliser Codex directement. Aucune clé n'est copiée entre les +outils. + +## F. Retour depuis Codex + +Lancer `/lardon-resume-from-codex`. OpenCode lit le handoff et le diff laissé +par Codex, puis effectue revue et tests sans refaire l'architecture. Le handoff +est ensuite actualisé. + +## G. GPT-5.6 Sol direct dans OpenCode + +Ce scénario est désactivé : Q1 n'est pas confirmé. Il ne pourra être ajouté que +si une route ChatGPT/Codex officiellement supportée, sans facturation Zen ou API +distincte, et une consommation du quota Codex sont toutes prouvées. + +## H. Authentification directe avec quota inconnu + +Le cas Q2 n'a pas été observé. S'il apparaît plus tard, aucune utilisation ne +doit être automatique : documenter le fournisseur et le risque, puis obtenir une +décision explicite avant une commande expérimentale. + +## I. Fallback payant interdit + +La configuration ne référence que des modèles explicitement gratuits. Une panne +de tous les secours gratuits arrête le ticket en conservant le handoff. Elle ne +doit jamais sélectionner `big-pickle`, GPT-5.6 Sol ou un autre modèle tarifé ou +de statut inconnu. + +## Chargement progressif + +1. Lire AGENTS.md et l'overview injectés par la configuration. +2. Faire identifier par explore les seuls fichiers et documents utiles. +3. Charger ces documents seulement ; appeler architect si une abstraction est + touchée. +4. Transmettre à l'implémenteur un résumé concis, jamais les documents complets. +5. Appeler uniquement les validations et revues pertinentes. + +Pour une reprise, commencer par le handoff et le diff. Les sorties intermédiaires +ne conservent que conclusions, risques, fichiers, commandes, erreurs et +décisions ; les longs logs et les sources complètes sont exclus. diff --git a/src/task_queue.c b/src/task_queue.c index 677bbb3..83e9f29 100644 --- a/src/task_queue.c +++ b/src/task_queue.c @@ -34,6 +34,82 @@ terminal_state(Lardon3DTaskState state) || state == TASK_COMPLETED; } +static void +unlink_pending(Lardon3DTaskQueue *queue, TaskNode *previous, TaskNode *node) +{ + if (previous) { + previous->next_pending = node->next_pending; + } else { + queue->pending_head = node->next_pending; + } + if (queue->pending_tail == node) { + queue->pending_tail = previous; + } + node->next_pending = NULL; +} + +/* Parcourt la file d'attente et sélectionne la première tâche admissible. + * Les tâches terminales ou refusées sont retirées de la file d'attente. + * Une tâche en attente de ressources reste en file et sera réévaluée. + * Retourne NULL si aucune tâche ne peut démarrer immédiatement. */ +static Lardon3DTask * +select_admissible( + Lardon3DTaskQueue *queue, + Lardon3DResourceReservation **reservation +) +{ + TaskNode *previous = NULL; + TaskNode *node = queue->pending_head; + while (node) { + TaskNode *next = node->next_pending; + Lardon3DTaskSnapshot task_snapshot; + if (!lardon3d_task_snapshot(node->task, &task_snapshot)) { + unlink_pending(queue, previous, node); + node = next; + continue; + } + if (terminal_state(task_snapshot.state)) { + unlink_pending(queue, previous, node); + node = next; + continue; + } + Lardon3DResourceEstimate estimate; + Lardon3DResourceDecision decision; + Lardon3DResourceReservation *candidate = NULL; + bool evaluated = lardon3d_task_resource_estimate(node->task, &estimate) + && lardon3d_resource_governor_reserve_available( + queue->governor, + &estimate, + &decision, + &candidate + ); + if (!evaluated) { + (void)lardon3d_task_reject( + node->task, + "Impossible d'évaluer les ressources disponibles." + ); + unlink_pending(queue, previous, node); + node = next; + continue; + } + if (decision.kind == LARDON3D_RESOURCE_WAIT) { + previous = node; + node = next; + continue; + } + if (decision.kind == LARDON3D_RESOURCE_REJECT || !candidate) { + (void)lardon3d_task_reject(node->task, decision.reason); + unlink_pending(queue, previous, node); + node = next; + continue; + } + unlink_pending(queue, previous, node); + *reservation = candidate; + return node->task; + } + return NULL; +} + static void * queue_worker(void *context) { @@ -47,64 +123,19 @@ queue_worker(void *context) (void)pthread_mutex_unlock(&queue->mutex); return NULL; } - TaskNode *node = queue->pending_head; - Lardon3DTaskSnapshot task_snapshot; - if (!lardon3d_task_snapshot(node->task, &task_snapshot)) { - (void)pthread_mutex_unlock(&queue->mutex); - continue; - } - if (terminal_state(task_snapshot.state)) { - queue->pending_head = node->next_pending; - if (!queue->pending_head) { - queue->pending_tail = NULL; - } - node->next_pending = NULL; - (void)pthread_mutex_unlock(&queue->mutex); - continue; - } - Lardon3DResourceEstimate estimate; - Lardon3DResourceDecision decision; Lardon3DResourceReservation *reservation = NULL; - bool evaluated = lardon3d_task_resource_estimate(node->task, &estimate) - && lardon3d_resource_governor_reserve_available( - queue->governor, - &estimate, - &decision, - &reservation - ); - if (!evaluated) { - (void)lardon3d_task_reject( - node->task, - "Impossible d'évaluer les ressources disponibles." - ); - (void)pthread_mutex_unlock(&queue->mutex); - continue; - } - if (decision.kind == LARDON3D_RESOURCE_WAIT) { + Lardon3DTask *selected = select_admissible(queue, &reservation); + if (!selected) { (void)pthread_cond_wait(&queue->condition, &queue->mutex); (void)pthread_mutex_unlock(&queue->mutex); continue; } - if (decision.kind == LARDON3D_RESOURCE_REJECT || !reservation) { - (void)lardon3d_task_reject(node->task, decision.reason); - (void)pthread_mutex_unlock(&queue->mutex); - continue; - } - queue->pending_head = node->next_pending; - if (!queue->pending_head) { - queue->pending_tail = NULL; - } - node->next_pending = NULL; - queue->active = node->task; + queue->active = selected; (void)pthread_mutex_unlock(&queue->mutex); - if (!lardon3d_task_start( - node->task, - queue->governor, - reservation - )) { + if (!lardon3d_task_start(selected, queue->governor, reservation)) { (void)lardon3d_task_reject( - node->task, + selected, "Réservation de ressources invalide." ); } @@ -290,14 +321,7 @@ lardon3d_task_queue_remove(Lardon3DTaskQueue *queue, uint64_t task_id) pending = pending->next_pending; } if (pending) { - if (pending_previous) { - pending_previous->next_pending = pending->next_pending; - } else { - queue->pending_head = pending->next_pending; - } - if (queue->pending_tail == pending) { - queue->pending_tail = pending_previous; - } + unlink_pending(queue, pending_previous, pending); } --queue->count; (void)pthread_mutex_unlock(&queue->mutex); diff --git a/tests/test_task_queue.c b/tests/test_task_queue.c index 0e84cba..366426c 100644 --- a/tests/test_task_queue.c +++ b/tests/test_task_queue.c @@ -296,6 +296,74 @@ run_test(void) lardon3d_task_queue_destroy(queue); CHECK(pthread_mutex_destroy(&wait_log.mutex) == 0); + /* Une tâche de tête bloquée en WAIT ne doit pas empêcher une tâche + admissible située derrière elle de démarrer. */ + Lardon3DResourceSnapshot io_blocking_snapshot = { + .memory_available_bytes = UINT64_MAX, + .cpu_load_1m = 0.0, + }; + Lardon3DResourceEstimate io_blocking_estimate = { + .minimum_batch_size = 1, + .maximum_batch_size = 1, + .desired_cpu_threads = 1, + .desired_io_slots = 1, + }; + Lardon3DResourceDecision io_decision; + Lardon3DResourceReservation *io_blocking_reservation; + CHECK(lardon3d_resource_governor_reserve( + governor, + &io_blocking_snapshot, + &io_blocking_estimate, + &io_decision, + &io_blocking_reservation + )); + CHECK(io_blocking_reservation); + queue = lardon3d_task_queue_create(governor); + CHECK(queue); + OrderLog bypass_log = {0}; + CHECK(pthread_mutex_init(&bypass_log.mutex, NULL) == 0); + Lardon3DResourceEstimate io_estimate = { + .minimum_batch_size = 1, + .maximum_batch_size = 1, + .desired_cpu_threads = 1, + .desired_io_slots = 1, + }; + QueueWork blocked = {.log = &bypass_log, .value = 1, .steps = 1}; + Lardon3DTask *blocked_task = lardon3d_task_create( + "Bloquée en tête", + &io_estimate, + queue_callback, + &blocked + ); + uint64_t blocked_id; + CHECK(blocked_task); + CHECK(lardon3d_task_queue_add(queue, blocked_task, &blocked_id)); + QueueWork bypass = {.log = &bypass_log, .value = 2, .steps = 1}; + Lardon3DTask *bypass_task = lardon3d_task_create( + "Admissible derrière", + &estimate, + queue_callback, + &bypass + ); + uint64_t bypass_id; + CHECK(bypass_task); + CHECK(lardon3d_task_queue_add(queue, bypass_task, &bypass_id)); + CHECK(wait_terminal(queue, bypass_id, &snapshot)); + CHECK(snapshot.state == TASK_COMPLETED); + CHECK(bypass.contract_seen); + CHECK(lardon3d_task_queue_get(queue, blocked_id, &snapshot)); + CHECK(snapshot.state == TASK_PENDING); + CHECK(!blocked.contract_seen); + CHECK(lardon3d_resource_governor_release(governor, io_blocking_reservation)); + lardon3d_task_queue_resources_changed(queue); + CHECK(wait_terminal(queue, blocked_id, &snapshot)); + CHECK(snapshot.state == TASK_COMPLETED); + CHECK(blocked.contract_seen); + CHECK(bypass_log.count == 2); + CHECK(lardon3d_resource_governor_reservation_count(governor) == 0); + lardon3d_task_queue_destroy(queue); + CHECK(pthread_mutex_destroy(&bypass_log.mutex) == 0); + queue = lardon3d_task_queue_create(governor); CHECK(queue); OrderLog contract_log = {0};