new day
This commit is contained in:
parent
44e8e0892e
commit
4622aa3b93
18 changed files with 1579 additions and 77 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
description: Explore rapidement fichiers, symboles, appels et dépendances
|
description: Explore rapidement fichiers, symboles, appels et dépendances
|
||||||
mode: subagent
|
mode: subagent
|
||||||
model: opencode/north-mini-code-free
|
model: opencode/mimo-v2.5-free
|
||||||
temperature: 0.1
|
temperature: 0.1
|
||||||
permission:
|
permission:
|
||||||
edit: deny
|
edit: deny
|
||||||
|
|
@ -16,3 +16,39 @@ Travaille en lecture seule. Localise exactement les fichiers, symboles,
|
||||||
appelants, dépendances et documents strictement utiles. Ne lis pas toute
|
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
|
l'architecture par défaut, ne propose pas de réécriture et retourne uniquement
|
||||||
les chemins, conclusions et risques synthétiques.
|
les chemins, conclusions et risques synthétiques.
|
||||||
|
|
||||||
|
Tu reçois obligatoirement une liste de symboles, modules ou chemins précis.
|
||||||
|
|
||||||
|
Si la demande ne fournit aucun élément précis, refuse l’exploration et demande
|
||||||
|
au parent de préciser la cible.
|
||||||
|
|
||||||
|
Interdictions absolues :
|
||||||
|
|
||||||
|
- pwd ;
|
||||||
|
- ls ;
|
||||||
|
- find ;
|
||||||
|
- glob global ;
|
||||||
|
- **/*.c ;
|
||||||
|
- **/*.h ;
|
||||||
|
- inventaire du dépôt ;
|
||||||
|
- lecture de toute la documentation.
|
||||||
|
|
||||||
|
Utilise uniquement des recherches ciblées avec rg sur les chemins ou symboles
|
||||||
|
fournis.
|
||||||
|
|
||||||
|
Lis au maximum :
|
||||||
|
|
||||||
|
- cinq fichiers source ou headers ;
|
||||||
|
- deux fichiers de tests ;
|
||||||
|
- deux documents d’architecture.
|
||||||
|
|
||||||
|
Retourne seulement :
|
||||||
|
|
||||||
|
- fichiers pertinents ;
|
||||||
|
- symboles pertinents ;
|
||||||
|
- dépendances directes ;
|
||||||
|
- risques ;
|
||||||
|
- informations encore manquantes.
|
||||||
|
|
||||||
|
Ne propose aucune nouvelle fonctionnalité.
|
||||||
|
Ne modifie aucun fichier.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
description: Orchestre les tickets avec un contexte minimal et sans écrire les sources
|
description: Orchestre les tickets avec un contexte minimal et sans écrire les sources
|
||||||
mode: primary
|
mode: primary
|
||||||
model: opencode/north-mini-code-free
|
model: opencode/mimo-v2.5-free
|
||||||
temperature: 0.1
|
temperature: 0.1
|
||||||
permission:
|
permission:
|
||||||
edit:
|
edit:
|
||||||
|
|
@ -25,8 +25,66 @@ permission:
|
||||||
"lardon-docs": allow
|
"lardon-docs": allow
|
||||||
---
|
---
|
||||||
|
|
||||||
Orchestre sans modifier les sources. Charge AGENTS.md et l'overview déjà
|
Le dépôt courant est déjà la racine de Lardon3D.
|
||||||
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é
|
Ne lance jamais de commande de découverte globale :
|
||||||
court : objectif, contraintes, fichiers, API, invariants et tests. Tiens le
|
|
||||||
handoff concis à jour après chaque phase. Aucun modèle payant, commit ou push.
|
- `pwd`
|
||||||
|
- `ls` ou `ls -la`
|
||||||
|
- `find` sur tout le dépôt
|
||||||
|
- glob `*`
|
||||||
|
- inventaire complet des fichiers
|
||||||
|
- lecture automatique de toute la documentation
|
||||||
|
|
||||||
|
AGENTS.md et l’overview sont déjà injectés comme instructions projet. Ne les relis
|
||||||
|
pas intégralement sauf si une information précise manque.
|
||||||
|
|
||||||
|
Pour chaque ticket :
|
||||||
|
|
||||||
|
1. Lire `.opencode/work/current_ticket.md` s’il existe.
|
||||||
|
2. Identifier uniquement les modules, symboles et fichiers liés au ticket.
|
||||||
|
3. Utiliser `lardon-explore` avec une requête ciblée.
|
||||||
|
4. Charger uniquement les documents d’architecture directement pertinents.
|
||||||
|
5. Appeler seulement les agents nécessaires.
|
||||||
|
|
||||||
|
Tout ticket touchant au moins un des éléments suivants exige obligatoirement
|
||||||
|
`lardon-concurrency` :
|
||||||
|
|
||||||
|
- `task`
|
||||||
|
- `task_queue`
|
||||||
|
- scheduler
|
||||||
|
- `resource_governor`
|
||||||
|
- pthread
|
||||||
|
- mutex
|
||||||
|
- variable de condition
|
||||||
|
- pause ou reprise
|
||||||
|
- annulation
|
||||||
|
- réservation
|
||||||
|
- état ou durée de vie partagés entre threads
|
||||||
|
|
||||||
|
Cette règle s’applique même si le ticket ne crée aucun nouveau thread.
|
||||||
|
|
||||||
|
6. Transmettre au seul agent implémenteur un résumé court contenant :
|
||||||
|
- objectif ;
|
||||||
|
- contraintes ;
|
||||||
|
- fichiers concernés ;
|
||||||
|
- API et invariants ;
|
||||||
|
- tests requis.
|
||||||
|
7. Mettre à jour le handoff après chaque phase importante.
|
||||||
|
|
||||||
|
Le répertoire `.opencode/work/` est préparé localement. Ne vérifie pas son
|
||||||
|
existence avec Bash. Crée ou mets à jour directement
|
||||||
|
`.opencode/work/current_ticket.md` avec l’outil d’édition autorisé.
|
||||||
|
|
||||||
|
Ne modifie jamais les sources toi-même.
|
||||||
|
|
||||||
|
N’utilise jamais :
|
||||||
|
|
||||||
|
- de modèle payant ;
|
||||||
|
- de sous-agent imbriqué ;
|
||||||
|
- plusieurs agents d’écriture simultanément ;
|
||||||
|
- `git commit` ;
|
||||||
|
- `git push`.
|
||||||
|
|
||||||
|
Les rapports intermédiaires doivent être courts et ne contenir que les
|
||||||
|
conclusions, risques, fichiers concernés, tests et prochaines actions.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
description: Exécute les validations Lardon3D sans modifier le code
|
description: Exécute les validations Lardon3D sans modifier le code
|
||||||
mode: subagent
|
mode: subagent
|
||||||
model: opencode/north-mini-code-free
|
model: opencode/mimo-v2.5-free
|
||||||
temperature: 0.1
|
temperature: 0.1
|
||||||
permission:
|
permission:
|
||||||
edit: deny
|
edit: deny
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,125 @@
|
||||||
---
|
---
|
||||||
description: Planifier en lecture seule avec un contexte minimal
|
description: Planifier un ticket en lecture seule avec un contexte minimal
|
||||||
agent: lardon-orchestrator
|
agent: lardon-orchestrator
|
||||||
subtask: false
|
subtask: false
|
||||||
---
|
---
|
||||||
|
|
||||||
Planifie ce ticket sans modifier les sources : $ARGUMENTS
|
Planifie le ticket suivant sans modifier les sources :
|
||||||
|
|
||||||
Lis AGENTS.md et l'overview déjà chargés. Demande à lardon-explore uniquement
|
$ARGUMENTS
|
||||||
les modules concernés. Liste les fichiers et documents à charger, propose un plan
|
|
||||||
court et indique les agents réellement nécessaires. Écris dans
|
Le contexte permanent est déjà injecté depuis `.opencode/context.md`.
|
||||||
`.opencode/work/current_ticket.md` : titre, objectif, contraintes, fichiers,
|
|
||||||
documents utiles, plan, travail terminé/restant, fichiers modifiés, commandes,
|
Pour cette commande :
|
||||||
tests passés/restants, décisions, erreurs, modèle et prochaine action sûre.
|
|
||||||
|
- n'appelle aucun sous-agent ;
|
||||||
|
- ne lance aucune commande Bash ;
|
||||||
|
- ne modifie aucun fichier sauf
|
||||||
|
`.opencode/work/current_ticket.md`.
|
||||||
|
|
||||||
|
Ne lance jamais :
|
||||||
|
|
||||||
|
- `pwd`
|
||||||
|
- `ls`
|
||||||
|
- `find`
|
||||||
|
- glob
|
||||||
|
- inventaire du dépôt
|
||||||
|
- compilation
|
||||||
|
- tests
|
||||||
|
|
||||||
|
Réponds uniquement à partir :
|
||||||
|
|
||||||
|
- du contexte permanent ;
|
||||||
|
- du texte du ticket ;
|
||||||
|
- de `.opencode/work/current_ticket.md` s'il existe et concerne déjà ce ticket.
|
||||||
|
|
||||||
|
Si une information manque, indique simplement les deux ou trois fichiers qui
|
||||||
|
devront être lus lors d'une future exploration ciblée.
|
||||||
|
|
||||||
|
Ne tente jamais de les découvrir toi-même.
|
||||||
|
|
||||||
|
Choisis un seul ticket.
|
||||||
|
|
||||||
|
Ne fusionne jamais plusieurs tickets.
|
||||||
|
|
||||||
|
Ne propose jamais :
|
||||||
|
|
||||||
|
- de métrique ;
|
||||||
|
- de compteur ;
|
||||||
|
- de diagnostic ;
|
||||||
|
- de nouvelle API ;
|
||||||
|
- d'état TUI ;
|
||||||
|
- de fonctionnalité annexe ;
|
||||||
|
- de refactoring non demandé.
|
||||||
|
|
||||||
|
Le plan doit uniquement couvrir le périmètre demandé.
|
||||||
|
|
||||||
|
Dans la section **Agents nécessaires** :
|
||||||
|
|
||||||
|
- n'ajoute que les agents réellement utiles ;
|
||||||
|
- si le ticket touche `task`, `task_queue`, le scheduler,
|
||||||
|
`resource_governor`, pthread, mutex, variables de condition,
|
||||||
|
pause, reprise, annulation, réservations ou tout état partagé,
|
||||||
|
inclure obligatoirement `lardon-concurrency`,
|
||||||
|
même si aucun nouveau thread n'est créé.
|
||||||
|
|
||||||
|
Écris `.opencode/work/current_ticket.md`
|
||||||
|
une seule fois avec exactement cette structure :
|
||||||
|
|
||||||
|
Le handoff représente uniquement le ticket courant.
|
||||||
|
|
||||||
|
Si un nouveau ticket est demandé,
|
||||||
|
remplacer entièrement `.opencode/work/current_ticket.md`.
|
||||||
|
|
||||||
|
Ne jamais conserver plusieurs tickets simultanément.
|
||||||
|
|
||||||
|
Ne jamais demander quel ticket utiliser.
|
||||||
|
|
||||||
|
# Ticket
|
||||||
|
|
||||||
|
## Objectif
|
||||||
|
|
||||||
|
## Contraintes
|
||||||
|
|
||||||
|
## Fichiers probablement concernés
|
||||||
|
|
||||||
|
## Documents nécessaires
|
||||||
|
|
||||||
|
## Plan
|
||||||
|
|
||||||
|
## Agents nécessaires
|
||||||
|
|
||||||
|
## Agents non nécessaires
|
||||||
|
|
||||||
|
## Tests futurs
|
||||||
|
|
||||||
|
## Risques
|
||||||
|
|
||||||
|
## Prochaine action sûre
|
||||||
|
|
||||||
|
Contraintes :
|
||||||
|
|
||||||
|
- une seule occurrence de chaque rubrique ;
|
||||||
|
- aucun doublon ;
|
||||||
|
- aucun code inventé ;
|
||||||
|
- aucune API inventée ;
|
||||||
|
- aucune fonctionnalité hors périmètre ;
|
||||||
|
- aucune modification incrémentale répétée ;
|
||||||
|
- 80 lignes maximum.
|
||||||
|
|
||||||
|
Après l'écriture :
|
||||||
|
|
||||||
|
1. relire le fichier une seule fois ;
|
||||||
|
2. vérifier uniquement :
|
||||||
|
- structure ;
|
||||||
|
- absence de doublons ;
|
||||||
|
- cohérence ;
|
||||||
|
3. terminer immédiatement.
|
||||||
|
|
||||||
|
Ne fais aucun commit.
|
||||||
|
|
||||||
|
Ne fais aucun push.
|
||||||
|
|
||||||
|
N'utilise aucun modèle payant.
|
||||||
|
|
||||||
|
Ne modifie jamais `scan3d/`.
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,104 @@
|
||||||
---
|
---
|
||||||
description: Reprise rapide du handoff avec Nemotron
|
description: Reprendre rapidement un ticket avec Nemotron à partir du handoff
|
||||||
agent: lardon-orchestrator
|
agent: lardon-orchestrator
|
||||||
subtask: false
|
subtask: false
|
||||||
---
|
---
|
||||||
|
|
||||||
Reprends le ticket avec lardon-build-backup. Lis uniquement le handoff, le diff
|
Reprends le ticket suivant :
|
||||||
et les fichiers qu'ils citent. Ne refais ni exploration ni architecture si les
|
|
||||||
informations suffisent. Après l'implémentation, utilise lardon-build-light en
|
$ARGUMENTS
|
||||||
lecture seule pour une revue locale simple. N'appelle ni lardon-review ni
|
|
||||||
lardon-concurrency : signale l'absence de revue indépendante forte et diffère
|
Le contexte permanent de Lardon3D est déjà chargé via
|
||||||
toute revue de concurrence sensible jusqu'au prochain passage Codex. Mets le
|
`.opencode/context.md`.
|
||||||
handoff à jour avec la prochaine action sûre.
|
|
||||||
|
Commence toujours par :
|
||||||
|
|
||||||
|
1. lire `.opencode/work/current_ticket.md` ;
|
||||||
|
2. lire le diff courant.
|
||||||
|
|
||||||
|
Ne recharge jamais :
|
||||||
|
|
||||||
|
- AGENTS.md ;
|
||||||
|
- l'overview ;
|
||||||
|
- la documentation générale ;
|
||||||
|
- les documents d'architecture.
|
||||||
|
|
||||||
|
Ne relance jamais `lardon-explore` ou `lardon-architect` si le handoff contient
|
||||||
|
déjà :
|
||||||
|
|
||||||
|
- l'objectif ;
|
||||||
|
- les contraintes ;
|
||||||
|
- les fichiers concernés ;
|
||||||
|
- les invariants ;
|
||||||
|
- les validations réalisées ;
|
||||||
|
- le travail restant.
|
||||||
|
|
||||||
|
Ne lance une exploration supplémentaire que si une information indispensable est
|
||||||
|
absente.
|
||||||
|
|
||||||
|
Transmets à `lardon-build-backup` uniquement :
|
||||||
|
|
||||||
|
- l'objectif ;
|
||||||
|
- les contraintes ;
|
||||||
|
- les fichiers concernés ;
|
||||||
|
- les API concernées ;
|
||||||
|
- les invariants ;
|
||||||
|
- le travail restant ;
|
||||||
|
- la prochaine action sûre.
|
||||||
|
|
||||||
|
Ne renvoie jamais tout le handoff au modèle d'implémentation.
|
||||||
|
|
||||||
|
Après l'implémentation :
|
||||||
|
|
||||||
|
1. appeler `lardon-tests` une seule fois ;
|
||||||
|
2. utiliser `lardon-build-light` uniquement pour une première revue locale
|
||||||
|
simple ;
|
||||||
|
3. mettre à jour le handoff.
|
||||||
|
|
||||||
|
Ne pas appeler :
|
||||||
|
|
||||||
|
- `lardon-review` ;
|
||||||
|
- `lardon-concurrency` ;
|
||||||
|
|
||||||
|
car ils utilisent le même modèle que l'implémentation de secours.
|
||||||
|
|
||||||
|
Si le ticket touche notamment :
|
||||||
|
|
||||||
|
- pthread ;
|
||||||
|
- mutex ;
|
||||||
|
- condition variables ;
|
||||||
|
- scheduler ;
|
||||||
|
- task_queue ;
|
||||||
|
- resource_governor ;
|
||||||
|
- réservations ;
|
||||||
|
- synchronisation ;
|
||||||
|
|
||||||
|
signaler explicitement :
|
||||||
|
|
||||||
|
- qu'aucune revue indépendante forte n'a été réalisée ;
|
||||||
|
- que la revue de concurrence est différée au prochain passage Codex.
|
||||||
|
|
||||||
|
Le handoff doit rester court et contenir uniquement :
|
||||||
|
|
||||||
|
- objectif ;
|
||||||
|
- contraintes ;
|
||||||
|
- fichiers concernés ;
|
||||||
|
- travail effectué ;
|
||||||
|
- validations exécutées ;
|
||||||
|
- erreurs rencontrées ;
|
||||||
|
- limites restantes ;
|
||||||
|
- prochaine action sûre.
|
||||||
|
|
||||||
|
Règles :
|
||||||
|
|
||||||
|
- un seul agent écrit les sources ;
|
||||||
|
- aucun sous-agent imbriqué ;
|
||||||
|
- aucun modèle payant ;
|
||||||
|
- aucun commit ;
|
||||||
|
- aucun push ;
|
||||||
|
- aucune modification de `scan3d/`.
|
||||||
|
|
||||||
|
Objectif principal :
|
||||||
|
|
||||||
|
Reprendre un ticket en quelques secondes avec le plus petit contexte possible,
|
||||||
|
sans refaire l'analyse déjà présente dans le handoff.
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,72 @@ agent: lardon-orchestrator
|
||||||
subtask: false
|
subtask: false
|
||||||
---
|
---
|
||||||
|
|
||||||
Traite ce petit ticket : $ARGUMENTS
|
Traite le petit ticket suivant :
|
||||||
|
|
||||||
Utilise lardon-explore pour cibler les fichiers, puis un seul lardon-build-light
|
$ARGUMENTS
|
||||||
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.
|
Le contexte permanent de Lardon3D est déjà chargé via `.opencode/context.md`.
|
||||||
Appelle ensuite lardon-tests pour compilation, tests ciblés et
|
|
||||||
`git diff --check`, puis une revue seulement si le diff le justifie. Maintiens
|
Ne relis AGENTS.md, l’overview ou la documentation générale que si une information
|
||||||
le handoff concis. Aucun commit, push ou fallback payant.
|
précise manque.
|
||||||
|
|
||||||
|
Ce workflow est réservé aux modifications locales, simples et clairement
|
||||||
|
délimitées.
|
||||||
|
|
||||||
|
N’effectue jamais :
|
||||||
|
|
||||||
|
- d’inventaire global du dépôt ;
|
||||||
|
- de `glob "*"` ;
|
||||||
|
- de `find` sur tout le dépôt ;
|
||||||
|
- de lecture complète de la documentation ;
|
||||||
|
- de refactoring d’architecture non demandé.
|
||||||
|
|
||||||
|
Procédure :
|
||||||
|
|
||||||
|
1. Lire `.opencode/work/current_ticket.md` s’il existe et s’il concerne ce ticket.
|
||||||
|
2. Utiliser `lardon-explore` avec une recherche strictement ciblée.
|
||||||
|
3. Identifier uniquement :
|
||||||
|
- les fichiers à modifier ;
|
||||||
|
- les dépendances directes ;
|
||||||
|
- les tests concernés ;
|
||||||
|
- les éventuels documents à mettre à jour.
|
||||||
|
4. Vérifier que le ticket convient au mode léger.
|
||||||
|
5. Utiliser un seul `lardon-build-light` pour l’implémentation.
|
||||||
|
6. Appeler `lardon-tests` une seule fois après l’implémentation pour :
|
||||||
|
- compiler avec Clang ;
|
||||||
|
- exécuter les tests ciblés ;
|
||||||
|
- exécuter `git diff --check`.
|
||||||
|
7. Demander une revue uniquement si le diff le justifie réellement.
|
||||||
|
8. Mettre à jour le handoff avec un résumé concis.
|
||||||
|
|
||||||
|
N’appelle pas `lardon-architect`, `lardon-concurrency` ou `lardon-docs` sauf si
|
||||||
|
leur intervention est manifestement nécessaire.
|
||||||
|
|
||||||
|
Arrête le workflow léger et recommande `/lardon-ticket` ou Codex si le ticket
|
||||||
|
touche notamment :
|
||||||
|
|
||||||
|
- une API publique structurante ;
|
||||||
|
- `task`, `task_queue` ou `resource_governor` ;
|
||||||
|
- pthread, mutex ou condition variables ;
|
||||||
|
- la durée de vie complexe de ressources ;
|
||||||
|
- la persistance ou le rollback ;
|
||||||
|
- le scheduler, un futur DAG ou les réservations ;
|
||||||
|
- un refactoring réparti sur plusieurs modules ;
|
||||||
|
- une fondation sensible du projet.
|
||||||
|
|
||||||
|
Dans ce cas, ne tente aucune modification risquée avec MiMo.
|
||||||
|
|
||||||
|
Le handoff doit rester court et contenir seulement :
|
||||||
|
|
||||||
|
- objectif ;
|
||||||
|
- fichiers concernés ;
|
||||||
|
- travail effectué ;
|
||||||
|
- validations ;
|
||||||
|
- erreurs ;
|
||||||
|
- limites ;
|
||||||
|
- prochaine action sûre.
|
||||||
|
|
||||||
|
Ne fais aucun commit.
|
||||||
|
Ne fais aucun push.
|
||||||
|
N’utilise aucun modèle payant.
|
||||||
|
Ne modifie jamais `scan3d/`.
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,102 @@
|
||||||
---
|
---
|
||||||
description: Reprendre un ticket gratuit avec Nemotron après indisponibilité DeepSeek
|
description: Reprendre un ticket après indisponibilité de DeepSeek
|
||||||
agent: lardon-orchestrator
|
agent: lardon-orchestrator
|
||||||
subtask: false
|
subtask: false
|
||||||
---
|
---
|
||||||
|
|
||||||
Lis d'abord `.opencode/work/current_ticket.md` et le diff. Si le handoff suffit,
|
Reprends le ticket suivant :
|
||||||
ne refais pas l'exploration. Transmets seulement l'objectif, les fichiers, les
|
|
||||||
invariants, le travail restant et la prochaine action à lardon-build-backup.
|
$ARGUMENTS
|
||||||
Après reprise, appelle lardon-tests puis lardon-build-light en lecture seule pour
|
|
||||||
une première revue locale simple. N'appelle ni lardon-review ni
|
Le contexte permanent de Lardon3D est déjà chargé via
|
||||||
lardon-concurrency, car ils utilisent le même modèle que l'implémenteur. Si le
|
`.opencode/context.md`.
|
||||||
diff touche la concurrence, réserve sa revue au prochain passage Codex et
|
|
||||||
signale explicitement l'absence de revue indépendante forte. Mets à jour le
|
Commence toujours par :
|
||||||
handoff après chaque phase. Aucun modèle payant.
|
|
||||||
|
1. lire `.opencode/work/current_ticket.md` ;
|
||||||
|
2. lire le diff courant.
|
||||||
|
|
||||||
|
Si ces deux éléments décrivent correctement le ticket, ne relis pas :
|
||||||
|
|
||||||
|
- AGENTS.md ;
|
||||||
|
- l'overview ;
|
||||||
|
- la documentation générale ;
|
||||||
|
- les documents d'architecture.
|
||||||
|
|
||||||
|
Ne relance pas `lardon-explore` si le handoff contient déjà :
|
||||||
|
|
||||||
|
- l'objectif ;
|
||||||
|
- les contraintes ;
|
||||||
|
- les fichiers concernés ;
|
||||||
|
- les invariants ;
|
||||||
|
- le travail restant.
|
||||||
|
|
||||||
|
Relance `lardon-explore` uniquement lorsqu'une information indispensable est
|
||||||
|
absente.
|
||||||
|
|
||||||
|
Transmets à `lardon-build-backup` uniquement :
|
||||||
|
|
||||||
|
- l'objectif ;
|
||||||
|
- les contraintes ;
|
||||||
|
- les fichiers concernés ;
|
||||||
|
- les API concernées ;
|
||||||
|
- les invariants ;
|
||||||
|
- le travail restant ;
|
||||||
|
- la prochaine action sûre.
|
||||||
|
|
||||||
|
Ne renvoie jamais tout le handoff au modèle d'implémentation.
|
||||||
|
|
||||||
|
Après l'implémentation :
|
||||||
|
|
||||||
|
1. appeler `lardon-tests` une seule fois ;
|
||||||
|
2. utiliser `lardon-build-light` uniquement pour une première revue locale
|
||||||
|
simple ;
|
||||||
|
3. mettre à jour le handoff.
|
||||||
|
|
||||||
|
Ne pas appeler :
|
||||||
|
|
||||||
|
- `lardon-review` ;
|
||||||
|
- `lardon-concurrency` ;
|
||||||
|
|
||||||
|
car ils utilisent le même modèle que l'implémentation de secours.
|
||||||
|
|
||||||
|
Si le ticket touche notamment :
|
||||||
|
|
||||||
|
- pthread ;
|
||||||
|
- mutex ;
|
||||||
|
- condition variables ;
|
||||||
|
- scheduler ;
|
||||||
|
- task_queue ;
|
||||||
|
- resource_governor ;
|
||||||
|
- réservations ;
|
||||||
|
- synchronisation ;
|
||||||
|
|
||||||
|
signaler explicitement :
|
||||||
|
|
||||||
|
- qu'aucune revue indépendante forte n'a été réalisée ;
|
||||||
|
- que la revue de concurrence est différée au prochain passage Codex.
|
||||||
|
|
||||||
|
Le handoff doit rester court et contenir uniquement :
|
||||||
|
|
||||||
|
- objectif ;
|
||||||
|
- contraintes ;
|
||||||
|
- fichiers concernés ;
|
||||||
|
- travail effectué ;
|
||||||
|
- validations exécutées ;
|
||||||
|
- erreurs rencontrées ;
|
||||||
|
- limites restantes ;
|
||||||
|
- prochaine action sûre.
|
||||||
|
|
||||||
|
Règles :
|
||||||
|
|
||||||
|
- un seul agent écrit les sources ;
|
||||||
|
- aucun sous-agent imbriqué ;
|
||||||
|
- aucun modèle payant ;
|
||||||
|
- aucun commit ;
|
||||||
|
- aucun push ;
|
||||||
|
- aucune modification de `scan3d/`.
|
||||||
|
|
||||||
|
Objectif principal :
|
||||||
|
|
||||||
|
Reprendre un ticket en quelques secondes, avec le plus petit contexte possible,
|
||||||
|
sans refaire les analyses déjà présentes dans le handoff.
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,83 @@
|
||||||
---
|
---
|
||||||
description: Traiter un ticket gratuit avec contexte progressif et handoff
|
description: Traiter un ticket complet avec contexte progressif et handoff
|
||||||
agent: lardon-orchestrator
|
agent: lardon-orchestrator
|
||||||
subtask: false
|
subtask: false
|
||||||
---
|
---
|
||||||
|
|
||||||
Traite ce ticket : $ARGUMENTS
|
Traite le ticket suivant :
|
||||||
|
|
||||||
1. Initialise `.opencode/work/current_ticket.md` avec les rubriques prescrites.
|
$ARGUMENTS
|
||||||
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,
|
Le contexte permanent de Lardon3D est déjà chargé via
|
||||||
fallback payant ou modification de scan3d/.
|
`.opencode/context.md`.
|
||||||
|
|
||||||
|
Considère également AGENTS.md et le handoff courant comme déjà disponibles.
|
||||||
|
Ne les relis que lorsqu'une information précise manque.
|
||||||
|
|
||||||
|
N'effectue jamais :
|
||||||
|
|
||||||
|
- d'inventaire global du dépôt ;
|
||||||
|
- de `glob "*"` ;
|
||||||
|
- de `find` sur tout le dépôt ;
|
||||||
|
- de lecture complète de toute la documentation.
|
||||||
|
|
||||||
|
Procédure :
|
||||||
|
|
||||||
|
1. Initialiser `.opencode/work/current_ticket.md` avec les rubriques prescrites.
|
||||||
|
2. Utiliser `lardon-explore` avec une recherche strictement ciblée.
|
||||||
|
3. Identifier uniquement :
|
||||||
|
- les fichiers à modifier ;
|
||||||
|
- les dépendances directes ;
|
||||||
|
- les tests concernés ;
|
||||||
|
- les documents réellement utiles.
|
||||||
|
4. Charger uniquement ce contexte.
|
||||||
|
5. Appeler `lardon-architect` uniquement si une évolution d'architecture est
|
||||||
|
réellement nécessaire.
|
||||||
|
6. Transmettre à `lardon-build` un résumé concis contenant :
|
||||||
|
- objectif ;
|
||||||
|
- contraintes ;
|
||||||
|
- API concernées ;
|
||||||
|
- invariants ;
|
||||||
|
- fichiers ;
|
||||||
|
- validations attendues.
|
||||||
|
7. Après l'implémentation :
|
||||||
|
- appeler `lardon-tests` une seule fois ;
|
||||||
|
- appeler `lardon-review` une seule fois ;
|
||||||
|
- appeler `lardon-concurrency` uniquement si le ticket touche :
|
||||||
|
- pthread ;
|
||||||
|
- mutex ;
|
||||||
|
- condition variables ;
|
||||||
|
- scheduler ;
|
||||||
|
- task_queue ;
|
||||||
|
- resource_governor ;
|
||||||
|
- code concurrent.
|
||||||
|
8. Mettre à jour le handoff après chaque phase importante.
|
||||||
|
|
||||||
|
Le handoff doit rester court et contenir uniquement :
|
||||||
|
|
||||||
|
- objectif ;
|
||||||
|
- contraintes ;
|
||||||
|
- fichiers concernés ;
|
||||||
|
- travail effectué ;
|
||||||
|
- validations exécutées ;
|
||||||
|
- erreurs rencontrées ;
|
||||||
|
- limites restantes ;
|
||||||
|
- prochaine action sûre.
|
||||||
|
|
||||||
|
Règles :
|
||||||
|
|
||||||
|
- un seul agent écrit les sources ;
|
||||||
|
- aucun sous-agent imbriqué ;
|
||||||
|
- aucun agent inutile ;
|
||||||
|
- aucun modèle payant ;
|
||||||
|
- aucun commit ;
|
||||||
|
- aucun push ;
|
||||||
|
- aucune modification de `scan3d/`.
|
||||||
|
|
||||||
|
Privilégier systématiquement :
|
||||||
|
|
||||||
|
- le plus petit contexte possible ;
|
||||||
|
- le moins d'agents possible ;
|
||||||
|
- une seule compilation complète ;
|
||||||
|
- une seule revue ;
|
||||||
|
- une seule analyse de concurrence lorsque nécessaire.
|
||||||
|
|
|
||||||
341
.opencode/context.md
Normal file
341
.opencode/context.md
Normal file
|
|
@ -0,0 +1,341 @@
|
||||||
|
# Lardon3D – Persistent Context
|
||||||
|
|
||||||
|
## Project
|
||||||
|
|
||||||
|
Lardon3D est un moteur de photogrammétrie Linux écrit en C17.
|
||||||
|
|
||||||
|
Objectifs principaux :
|
||||||
|
|
||||||
|
- stabilité absolue ;
|
||||||
|
- faible consommation mémoire ;
|
||||||
|
- traitement par lots adaptatifs ;
|
||||||
|
- aucune saturation du système ;
|
||||||
|
- TUI toujours réactive ;
|
||||||
|
- architecture modulaire.
|
||||||
|
|
||||||
|
Le viewer Vulkan sera un processus séparé lisant uniquement des snapshots validés.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Compiler avec :
|
||||||
|
|
||||||
|
CC=clang meson setup build --wipe
|
||||||
|
meson compile -C build -j8
|
||||||
|
|
||||||
|
Validation minimale :
|
||||||
|
|
||||||
|
meson test -C build --print-errorlogs
|
||||||
|
git diff --check
|
||||||
|
|
||||||
|
Utiliser ASan/UBSan et TSan uniquement lorsque le ticket touche la mémoire ou la concurrence.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Git
|
||||||
|
|
||||||
|
Interdictions :
|
||||||
|
|
||||||
|
- jamais git add -A
|
||||||
|
- jamais git commit
|
||||||
|
- jamais git push
|
||||||
|
- jamais modifier scan3d/
|
||||||
|
- jamais modifier tri_photos.py
|
||||||
|
|
||||||
|
Toujours fournir :
|
||||||
|
|
||||||
|
- liste exacte des fichiers du ticket
|
||||||
|
- validations exécutées
|
||||||
|
- limites restantes
|
||||||
|
- message de commit recommandé
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
Séparation stricte :
|
||||||
|
|
||||||
|
TUI
|
||||||
|
↓
|
||||||
|
|
||||||
|
Scheduler
|
||||||
|
|
||||||
|
↓
|
||||||
|
|
||||||
|
Governor
|
||||||
|
|
||||||
|
↓
|
||||||
|
|
||||||
|
Workers
|
||||||
|
|
||||||
|
↓
|
||||||
|
|
||||||
|
Résultats atomiques
|
||||||
|
|
||||||
|
Le thread ncurses ne fait jamais de travail métier.
|
||||||
|
|
||||||
|
Le scheduler ne décide jamais des ressources.
|
||||||
|
|
||||||
|
Le gouverneur est le seul propriétaire des budgets.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Resource Governor
|
||||||
|
|
||||||
|
Estimate
|
||||||
|
|
||||||
|
↓
|
||||||
|
|
||||||
|
Reservation
|
||||||
|
|
||||||
|
↓
|
||||||
|
|
||||||
|
Scheduler
|
||||||
|
|
||||||
|
↓
|
||||||
|
|
||||||
|
Worker
|
||||||
|
|
||||||
|
Les réservations sont obligatoires avant toute exécution.
|
||||||
|
|
||||||
|
RAM iGPU partagée = RAM système.
|
||||||
|
|
||||||
|
La zram n'est jamais un budget de travail.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Coding rules
|
||||||
|
|
||||||
|
C17 uniquement.
|
||||||
|
|
||||||
|
Pas de variables globales d'état.
|
||||||
|
|
||||||
|
Pas de system().
|
||||||
|
|
||||||
|
Pas de popen().
|
||||||
|
|
||||||
|
Pas d'allocation infinie.
|
||||||
|
|
||||||
|
Toujours des buffers bornés.
|
||||||
|
|
||||||
|
Sorties atomiques.
|
||||||
|
|
||||||
|
Rollback complet en cas d'échec.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Current architecture
|
||||||
|
|
||||||
|
Modules disponibles :
|
||||||
|
|
||||||
|
- project
|
||||||
|
- import
|
||||||
|
- import_task
|
||||||
|
- image_catalog
|
||||||
|
- image_view
|
||||||
|
- task
|
||||||
|
- task_queue
|
||||||
|
- hardware_profile
|
||||||
|
- resource_snapshot
|
||||||
|
- resource_governor
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Active workflow
|
||||||
|
|
||||||
|
1. explorer uniquement les fichiers utiles
|
||||||
|
|
||||||
|
2. architect uniquement si nécessaire
|
||||||
|
|
||||||
|
3. un seul agent d'écriture
|
||||||
|
|
||||||
|
4. tests
|
||||||
|
|
||||||
|
5. revue
|
||||||
|
|
||||||
|
6. handoff
|
||||||
|
|
||||||
|
Ne jamais relire tout le dépôt.
|
||||||
|
|
||||||
|
Ne jamais faire de glob "*".
|
||||||
|
|
||||||
|
Ne jamais parcourir tous les fichiers.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Models
|
||||||
|
|
||||||
|
Primary orchestration
|
||||||
|
|
||||||
|
MiMo V2.5 Free
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
|
||||||
|
DeepSeek V4 Flash Free
|
||||||
|
|
||||||
|
Backup implementation
|
||||||
|
|
||||||
|
Nemotron 3 Ultra Free
|
||||||
|
|
||||||
|
Exploration
|
||||||
|
|
||||||
|
North Mini Code Free
|
||||||
|
|
||||||
|
Architecture / Review / Concurrency
|
||||||
|
|
||||||
|
Nemotron 3 Ultra Free
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
|
||||||
|
Ling 3.0 Flash Free
|
||||||
|
|
||||||
|
Aucun modèle payant.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## If DeepSeek fails
|
||||||
|
|
||||||
|
Reprendre depuis :
|
||||||
|
|
||||||
|
.opencode/work/current_ticket.md
|
||||||
|
|
||||||
|
Ne jamais refaire :
|
||||||
|
|
||||||
|
- exploration
|
||||||
|
- architecture
|
||||||
|
- revue
|
||||||
|
|
||||||
|
si le handoff contient déjà ces informations.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project roadmap
|
||||||
|
|
||||||
|
Fondations terminées :
|
||||||
|
|
||||||
|
- TUI modulaire
|
||||||
|
- projets persistants
|
||||||
|
- import asynchrone
|
||||||
|
- catalogue d'images
|
||||||
|
- image_view
|
||||||
|
- moteur de tâches
|
||||||
|
- scheduler FIFO
|
||||||
|
- gouverneur de ressources
|
||||||
|
- réservations
|
||||||
|
- intégration scheduler ↔ governor
|
||||||
|
- sélection de la première tâche admissible
|
||||||
|
- documentation d'architecture
|
||||||
|
|
||||||
|
Ordre obligatoire des prochains tickets :
|
||||||
|
|
||||||
|
1. séquences de traitement adaptatives pilotées par le Resource Governor
|
||||||
|
2. contre-pression (backpressure) et bornage des files
|
||||||
|
3. checkpoints et persistance des tâches
|
||||||
|
4. DAG minimal de dépendances
|
||||||
|
5. priorités
|
||||||
|
6. pools CPU / GPU / IO
|
||||||
|
7. migration de l'import vers le scheduler générique
|
||||||
|
8. publication incrémentale
|
||||||
|
9. viewer Vulkan
|
||||||
|
|
||||||
|
Ne jamais proposer un ticket déjà terminé.
|
||||||
|
|
||||||
|
Ne jamais sauter une étape de cette feuille de route sans justification explicite.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mission
|
||||||
|
|
||||||
|
Toujours privilégier :
|
||||||
|
|
||||||
|
- stabilité
|
||||||
|
- simplicité
|
||||||
|
- déterminisme
|
||||||
|
- faible mémoire
|
||||||
|
- traitements séquencés
|
||||||
|
- protection du système
|
||||||
|
|
||||||
|
avant les performances brutes.
|
||||||
|
|
||||||
|
État actuel important :
|
||||||
|
|
||||||
|
- Le scheduler sait déjà sauter une tâche en WAIT en tête de file.
|
||||||
|
- Il sélectionne la première tâche admissible dans l’ordre FIFO.
|
||||||
|
- Ce ticket est terminé et ne doit pas être reproposé.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Revue de concurrence obligatoire
|
||||||
|
|
||||||
|
Tout ticket touchant `task`, `task_queue`, le scheduler,
|
||||||
|
`resource_governor`, pthread, mutex, variables de condition, pause, reprise,
|
||||||
|
annulation, réservations ou états partagés exige `lardon-concurrency`.
|
||||||
|
|
||||||
|
Cette règle s’applique même si aucun nouveau thread n’est créé.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Design philosophy
|
||||||
|
|
||||||
|
Chaque étape du pipeline doit être :
|
||||||
|
|
||||||
|
- indépendante ;
|
||||||
|
- interruptible ;
|
||||||
|
- reprenable ;
|
||||||
|
- observable ;
|
||||||
|
- testable ;
|
||||||
|
- déterministe.
|
||||||
|
|
||||||
|
Chaque tâche doit pouvoir être découpée en petits lots afin de :
|
||||||
|
|
||||||
|
- limiter l'utilisation mémoire ;
|
||||||
|
- garder une TUI fluide ;
|
||||||
|
- permettre une adaptation dynamique des ressources ;
|
||||||
|
- éviter toute saturation du système.
|
||||||
|
|
||||||
|
La stabilité du système hôte est prioritaire sur les performances brutes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Long-term objective
|
||||||
|
|
||||||
|
Lardon3D doit devenir un moteur de photogrammétrie entièrement piloté par un
|
||||||
|
scheduler adaptatif.
|
||||||
|
|
||||||
|
Le scheduler décide uniquement :
|
||||||
|
|
||||||
|
- quand lancer une étape ;
|
||||||
|
- avec quel lot ;
|
||||||
|
- dans quel ordre.
|
||||||
|
|
||||||
|
Le Resource Governor décide uniquement :
|
||||||
|
|
||||||
|
- si les ressources permettent l'exécution ;
|
||||||
|
- la taille optimale des lots ;
|
||||||
|
- quand différer une tâche.
|
||||||
|
|
||||||
|
Le viewer Vulkan ne participe jamais aux calculs.
|
||||||
|
|
||||||
|
Il affiche uniquement des snapshots validés produits par le pipeline.
|
||||||
|
|
||||||
|
L'utilisateur doit voir le résultat apparaître progressivement pendant les
|
||||||
|
calculs, sans attendre la fin complète de la reconstruction.
|
||||||
|
|
||||||
|
Toutes les étapes doivent pouvoir être interrompues puis reprises sans perdre
|
||||||
|
les résultats déjà validés.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Optimisation
|
||||||
|
|
||||||
|
Privilégier toujours :
|
||||||
|
|
||||||
|
- plusieurs petits traitements ;
|
||||||
|
- plusieurs petites allocations ;
|
||||||
|
- plusieurs petites copies ;
|
||||||
|
|
||||||
|
plutôt qu'une grosse opération monolithique.
|
||||||
|
|
||||||
|
Lardon3D doit être optimisé pour des machines disposant de peu de mémoire
|
||||||
|
(16 à 32 Go) et d'un iGPU partagé.
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://opencode.ai/config.json",
|
"$schema": "https://opencode.ai/config.json",
|
||||||
"default_agent": "lardon-orchestrator",
|
"default_agent": "lardon-orchestrator",
|
||||||
"model": "opencode/north-mini-code-free",
|
"model": "opencode/mimo-v2.5-free",
|
||||||
"subagent_depth": 1,
|
"subagent_depth": 1,
|
||||||
"instructions": [
|
"instructions": [
|
||||||
"AGENTS.md",
|
"AGENTS.md",
|
||||||
|
".opencode/context.md",
|
||||||
"docs/architecture/overview.md"
|
"docs/architecture/overview.md"
|
||||||
],
|
],
|
||||||
"permission": {
|
"permission": {
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,47 @@ pendant `PAUSED`. Ses ressources restent donc indisponibles pour les autres
|
||||||
tâches. Ce choix évite de reprendre un callback avec un contrat qui aurait été
|
tâches. Ce choix évite de reprendre un callback avec un contrat qui aurait été
|
||||||
attribué entre-temps à un autre travail.
|
attribué entre-temps à un autre travail.
|
||||||
|
|
||||||
|
## Exécution séquencée adaptative
|
||||||
|
|
||||||
|
Une tâche peut s'exécuter en plusieurs séquences (lots) successives. Le
|
||||||
|
callback appelle `lardon3d_task_sequence_break()` pour libérer sa réservation
|
||||||
|
courante, capturer un nouvel instantané système, obtenir une nouvelle
|
||||||
|
réservation auprès du gouverneur et reprendre avec un contrat actualisé.
|
||||||
|
|
||||||
|
Le cycle d'une séquence est strict :
|
||||||
|
|
||||||
|
```text
|
||||||
|
Callback
|
||||||
|
→ sequence_break
|
||||||
|
→ Release Reservation courante
|
||||||
|
→ Snapshot système
|
||||||
|
→ Governor → Reservation
|
||||||
|
→ Contrat actualisé
|
||||||
|
→ Reprise du callback
|
||||||
|
```
|
||||||
|
|
||||||
|
Le task conserve une référence au gouverneur et à sa réservation courante.
|
||||||
|
`lardon3d_task_start` stocke la réservation initiale ; à la fin de l'exécution,
|
||||||
|
il libère la réservation courante si elle est encore détenue. Le worker de la
|
||||||
|
file libère ensuite la réservation d'origine, qui est déjà libérée si une
|
||||||
|
séquence a eu lieu : cet appel est alors sans effet.
|
||||||
|
|
||||||
|
Invariants préservés :
|
||||||
|
|
||||||
|
- Aucun callback ne démarre sans réservation active.
|
||||||
|
- Une seule réservation active par tâche à tout instant.
|
||||||
|
- La réservation est toujours valide avant et après un `sequence_break`.
|
||||||
|
- Le contrat est mis à jour atomiquement sous le mutex de la tâche.
|
||||||
|
- Si pause ou annulation est demandée pendant le `sequence_break`, la fonction
|
||||||
|
retourne `false` et la tâche est annulée.
|
||||||
|
- Si le gouverneur répond `WAIT` ou `REJECT`, la fonction retourne `false` et
|
||||||
|
la tâche passe en échec sans bloquer le callback.
|
||||||
|
- La progression est conservée entre les séquences.
|
||||||
|
|
||||||
## Limites et extensions
|
## Limites et extensions
|
||||||
|
|
||||||
La file possède un seul worker, reste strictement FIFO et ne gère ni priorité
|
La file possède un seul worker, reste strictement FIFO et ne gère ni priorité
|
||||||
ni dépendance. Une notification explicite est nécessaire lorsqu'un composant
|
ni dépendance. Une notification explicite est nécessaire lorsqu'un composant
|
||||||
extérieur libère une réservation. Les prochaines étapes pourront ajouter un
|
extérieur libère une réservation. Les prochaines étapes pourront ajouter un
|
||||||
DAG, des priorités, des séquences de lots adaptatives et des pools distincts
|
DAG, des priorités, des pools distincts CPU, IO et GPU sans déplacer les
|
||||||
CPU, IO et GPU sans déplacer les décisions de ressources hors du gouverneur.
|
décisions de ressources hors du gouverneur.
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,11 @@ entrée, sortie et cache :
|
||||||
recommandé `opencode/nemotron-3-ultra-free` en cas de saturation 503.
|
recommandé `opencode/nemotron-3-ultra-free` en cas de saturation 503.
|
||||||
- `opencode/nemotron-3-ultra-free` : architecture, concurrence, revue et repli
|
- `opencode/nemotron-3-ultra-free` : architecture, concurrence, revue et repli
|
||||||
de l'agent principal.
|
de l'agent principal.
|
||||||
- `opencode/north-mini-code-free` : exploration rapide et validations.
|
- `opencode/mimo-v2.5-free` : exploration rapide et validations.
|
||||||
- `opencode/laguna-s-2.1-free` : testé comme reviewer sur Lardon3D ; résultats
|
- `opencode/laguna-s-2.1-free` : testé comme reviewer sur Lardon3D ; résultats
|
||||||
jugés insuffisants. Non utilisé dans les rôles actifs.
|
jugés insuffisants. Non utilisé dans les rôles actifs.
|
||||||
- `opencode/ling-3.0-flash-free` : documentation.
|
- `opencode/ling-3.0-flash-free` : documentation.
|
||||||
- `opencode/longcat-2.0-free` : disponible, non configuré actuellement.
|
- `opencode/longcat-2.0-free` : disponible, non configuré actuellement.
|
||||||
- `opencode/mimo-v2.5-free` : disponible, non configuré actuellement.
|
|
||||||
|
|
||||||
## Gratuité non confirmée
|
## Gratuité non confirmée
|
||||||
|
|
||||||
|
|
@ -63,24 +62,66 @@ OpenCode actuelle.
|
||||||
|
|
||||||
## Optimisation du quota
|
## Optimisation du quota
|
||||||
|
|
||||||
L'agent par défaut est `lardon-orchestrator` sur North Mini Code Free. Il charge
|
L’agent par défaut est `lardon-orchestrator` sur MiMo V2.5 Free.
|
||||||
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, revues et analyses d'architecture ou de concurrence, MiMo les petits
|
|
||||||
tickets et Ling la documentation.
|
|
||||||
|
|
||||||
Les commandes `lardon-plan`, `lardon-small`, `lardon-ticket` et
|
Le contexte permanent est chargé depuis `.opencode/context.md`. L’orchestrateur
|
||||||
`lardon-ticket-backup` chargent progressivement le contexte. Elles ne lisent pas
|
ne relit pas automatiquement AGENTS.md, l’overview ni toute la documentation
|
||||||
automatiquement toute l'architecture et transmettent uniquement objectif,
|
d’architecture. Il utilise uniquement le handoff courant et les documents
|
||||||
contraintes, fichiers, API, invariants, risques et tests. Les rapports de succès
|
directement liés au ticket.
|
||||||
restent courts. Le handoff ignoré `.opencode/work/current_ticket.md` permet une
|
|
||||||
reprise sans rejouer toute l'analyse.
|
|
||||||
|
|
||||||
Nemotron ne relit jamais sa propre implémentation lorsqu'il a servi de backup.
|
MiMo assure :
|
||||||
MiMo fournit alors seulement une première revue locale simple. La revue de
|
|
||||||
concurrence sensible est différée jusqu'au prochain passage Codex, et le workflow
|
- l’orchestration ;
|
||||||
signale explicitement qu'aucune revue indépendante forte n'a eu lieu.
|
- l’exploration ciblée ;
|
||||||
|
- les tests ;
|
||||||
|
- les petits tickets.
|
||||||
|
|
||||||
|
DeepSeek V4 Flash Free est réservé à l’implémentation complexe. Il ne sert ni à
|
||||||
|
l’orchestration, ni à l’exploration, ni aux tests, ni à la documentation.
|
||||||
|
|
||||||
|
Nemotron 3 Ultra Free assure :
|
||||||
|
|
||||||
|
- les reprises après indisponibilité de DeepSeek ;
|
||||||
|
- l’architecture ;
|
||||||
|
- la concurrence ;
|
||||||
|
- la revue générale.
|
||||||
|
|
||||||
|
Ling 3.0 Flash Free est réservé à la documentation.
|
||||||
|
|
||||||
|
North Mini Code Free n’est plus utilisé dans les rôles actifs. Il reste mentionné
|
||||||
|
dans l’inventaire historique comme modèle testé puis écarté en raison de résultats
|
||||||
|
jugés insuffisants et trop erratiques sur Lardon3D.
|
||||||
|
|
||||||
|
Les commandes `lardon-plan`, `lardon-small`, `lardon-ticket`,
|
||||||
|
`lardon-ticket-backup` et les commandes de reprise utilisent un contexte
|
||||||
|
progressif.
|
||||||
|
|
||||||
|
Elles ne lisent jamais automatiquement tout le dépôt ni toute l’architecture.
|
||||||
|
Elles transmettent uniquement :
|
||||||
|
|
||||||
|
- objectif ;
|
||||||
|
- contraintes ;
|
||||||
|
- fichiers concernés ;
|
||||||
|
- API ;
|
||||||
|
- invariants ;
|
||||||
|
- risques ;
|
||||||
|
- tests requis ;
|
||||||
|
- prochaine action sûre.
|
||||||
|
|
||||||
|
Les rapports de succès restent courts. Le handoff ignoré
|
||||||
|
`.opencode/work/current_ticket.md` permet une reprise sans rejouer l’exploration
|
||||||
|
ou l’analyse déjà terminée.
|
||||||
|
|
||||||
|
Nemotron ne relit jamais sa propre implémentation lorsqu’il a servi de backup.
|
||||||
|
|
||||||
|
Dans ce cas :
|
||||||
|
|
||||||
|
- MiMo fournit seulement une première revue locale simple ;
|
||||||
|
- la revue de concurrence sensible est différée jusqu’au prochain passage Codex ;
|
||||||
|
- le workflow signale explicitement qu’aucune revue indépendante forte n’a eu
|
||||||
|
lieu.
|
||||||
|
|
||||||
|
Aucun modèle payant n’est utilisé automatiquement.
|
||||||
|
|
||||||
## Chaîne de secours
|
## Chaîne de secours
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,17 @@ bool lardon3d_task_execution_contract(
|
||||||
const Lardon3DTask *task,
|
const Lardon3DTask *task,
|
||||||
Lardon3DTaskExecutionContract *contract
|
Lardon3DTaskExecutionContract *contract
|
||||||
);
|
);
|
||||||
|
/* Libère la réservation courante, en obtient une nouvelle auprès du gouverneur
|
||||||
|
* et met à jour le contrat. À appeler uniquement depuis le callback en cours
|
||||||
|
* d'exécution. Retourne false si pause/annulation est demandée ou si le
|
||||||
|
* gouverneur répond WAIT/REJECT (la tâche passe alors en échec). */
|
||||||
|
bool lardon3d_task_sequence_break(
|
||||||
|
Lardon3DTask *task,
|
||||||
|
Lardon3DResourceGovernor *governor,
|
||||||
|
Lardon3DResourceReservation **out_reservation,
|
||||||
|
Lardon3DTaskExecutionContract *out_contract
|
||||||
|
);
|
||||||
|
unsigned int lardon3d_task_sequence_count(const Lardon3DTask *task);
|
||||||
bool lardon3d_task_reject(Lardon3DTask *task, const char *message);
|
bool lardon3d_task_reject(Lardon3DTask *task, const char *message);
|
||||||
const char *lardon3d_task_state_name(Lardon3DTaskState state);
|
const char *lardon3d_task_state_name(Lardon3DTaskState state);
|
||||||
|
|
||||||
|
|
|
||||||
14
meson.build
14
meson.build
|
|
@ -111,6 +111,20 @@ task_test = executable(
|
||||||
|
|
||||||
test('task', task_test, timeout: 30)
|
test('task', task_test, timeout: 30)
|
||||||
|
|
||||||
|
sequential_task_test = executable(
|
||||||
|
'test-sequential-task',
|
||||||
|
sources: [
|
||||||
|
'tests/test_sequential_task.c',
|
||||||
|
'src/task.c',
|
||||||
|
'src/resource_governor.c',
|
||||||
|
'src/resource_snapshot.c',
|
||||||
|
],
|
||||||
|
include_directories: include_directories('include'),
|
||||||
|
dependencies: [threads],
|
||||||
|
)
|
||||||
|
|
||||||
|
test('sequential-task', sequential_task_test, timeout: 30)
|
||||||
|
|
||||||
task_queue_test = executable(
|
task_queue_test = executable(
|
||||||
'test-task-queue',
|
'test-task-queue',
|
||||||
sources: [
|
sources: [
|
||||||
|
|
|
||||||
153
src/task.c
153
src/task.c
|
|
@ -23,6 +23,9 @@ struct Lardon3DTask {
|
||||||
bool pause_requested;
|
bool pause_requested;
|
||||||
bool cancel_requested;
|
bool cancel_requested;
|
||||||
bool executing;
|
bool executing;
|
||||||
|
Lardon3DResourceGovernor *governor;
|
||||||
|
Lardon3DResourceReservation *current_reservation;
|
||||||
|
unsigned int sequence_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -125,6 +128,8 @@ lardon3d_task_start(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
task->executing = true;
|
task->executing = true;
|
||||||
|
task->governor = governor;
|
||||||
|
task->current_reservation = (Lardon3DResourceReservation *)reservation;
|
||||||
task->contract = (Lardon3DTaskExecutionContract) {
|
task->contract = (Lardon3DTaskExecutionContract) {
|
||||||
.batch_size = information.batch_size,
|
.batch_size = information.batch_size,
|
||||||
.memory_bytes = information.memory_bytes,
|
.memory_bytes = information.memory_bytes,
|
||||||
|
|
@ -143,6 +148,7 @@ lardon3d_task_start(
|
||||||
while (task->pause_requested && !task->cancel_requested) {
|
while (task->pause_requested && !task->cancel_requested) {
|
||||||
task->state = TASK_PAUSED;
|
task->state = TASK_PAUSED;
|
||||||
copy_text(task->message, sizeof(task->message), "Tâche en pause.");
|
copy_text(task->message, sizeof(task->message), "Tâche en pause.");
|
||||||
|
(void)pthread_cond_broadcast(&task->condition);
|
||||||
(void)pthread_cond_wait(&task->condition, &task->mutex);
|
(void)pthread_cond_wait(&task->condition, &task->mutex);
|
||||||
}
|
}
|
||||||
if (task->cancel_requested) {
|
if (task->cancel_requested) {
|
||||||
|
|
@ -169,6 +175,13 @@ lardon3d_task_start(
|
||||||
finish_locked(task, TASK_COMPLETED, "Tâche terminée.");
|
finish_locked(task, TASK_COMPLETED, "Tâche terminée.");
|
||||||
}
|
}
|
||||||
(void)pthread_mutex_unlock(&task->mutex);
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
|
if (task->current_reservation) {
|
||||||
|
(void)lardon3d_resource_governor_release(
|
||||||
|
governor,
|
||||||
|
task->current_reservation
|
||||||
|
);
|
||||||
|
task->current_reservation = NULL;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,6 +278,146 @@ lardon3d_task_checkpoint(Lardon3DTask *task)
|
||||||
return continuing;
|
return continuing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
lardon3d_task_sequence_break(
|
||||||
|
Lardon3DTask *task,
|
||||||
|
Lardon3DResourceGovernor *governor,
|
||||||
|
Lardon3DResourceReservation **out_reservation,
|
||||||
|
Lardon3DTaskExecutionContract *out_contract
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (!task || !governor || !out_reservation || !out_contract) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*out_reservation = NULL;
|
||||||
|
(void)pthread_mutex_lock(&task->mutex);
|
||||||
|
if (!task->executing || is_terminal(task->state)) {
|
||||||
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (task->pause_requested && !task->cancel_requested) {
|
||||||
|
task->state = TASK_PAUSED;
|
||||||
|
copy_text(task->message, sizeof(task->message), "Tâche en pause.");
|
||||||
|
(void)pthread_cond_broadcast(&task->condition);
|
||||||
|
(void)pthread_cond_wait(&task->condition, &task->mutex);
|
||||||
|
}
|
||||||
|
if (task->cancel_requested) {
|
||||||
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
task->state = TASK_RUNNING;
|
||||||
|
Lardon3DResourceReservation *previous = task->current_reservation;
|
||||||
|
task->current_reservation = NULL;
|
||||||
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
|
|
||||||
|
if (previous) {
|
||||||
|
(void)lardon3d_resource_governor_release(governor, previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
Lardon3DResourceDecision decision;
|
||||||
|
Lardon3DResourceReservation *next = NULL;
|
||||||
|
bool reserved = lardon3d_resource_governor_reserve_available(
|
||||||
|
governor,
|
||||||
|
&task->estimate,
|
||||||
|
&decision,
|
||||||
|
&next
|
||||||
|
);
|
||||||
|
|
||||||
|
(void)pthread_mutex_lock(&task->mutex);
|
||||||
|
if (task->cancel_requested) {
|
||||||
|
if (next) {
|
||||||
|
(void)lardon3d_resource_governor_release(governor, next);
|
||||||
|
}
|
||||||
|
finish_locked(
|
||||||
|
task,
|
||||||
|
TASK_CANCELLED,
|
||||||
|
"Tâche annulée pendant sequence_break."
|
||||||
|
);
|
||||||
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (task->pause_requested && !task->cancel_requested) {
|
||||||
|
task->state = TASK_PAUSED;
|
||||||
|
copy_text(task->message, sizeof(task->message), "Tâche en pause.");
|
||||||
|
(void)pthread_cond_broadcast(&task->condition);
|
||||||
|
(void)pthread_cond_wait(&task->condition, &task->mutex);
|
||||||
|
}
|
||||||
|
if (task->cancel_requested) {
|
||||||
|
if (next) {
|
||||||
|
(void)lardon3d_resource_governor_release(governor, next);
|
||||||
|
}
|
||||||
|
finish_locked(task, TASK_CANCELLED, "Tâche annulée.");
|
||||||
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!reserved || !next) {
|
||||||
|
task->current_reservation = NULL;
|
||||||
|
finish_locked(
|
||||||
|
task,
|
||||||
|
TASK_FAILED,
|
||||||
|
"Impossible de réserver les ressources de la séquence."
|
||||||
|
);
|
||||||
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (decision.kind == LARDON3D_RESOURCE_WAIT
|
||||||
|
|| decision.kind == LARDON3D_RESOURCE_REJECT) {
|
||||||
|
task->current_reservation = NULL;
|
||||||
|
finish_locked(
|
||||||
|
task,
|
||||||
|
TASK_FAILED,
|
||||||
|
decision.reason[0] ? decision.reason
|
||||||
|
: "Ressources impossibles à réserver."
|
||||||
|
);
|
||||||
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Lardon3DResourceReservationInfo information;
|
||||||
|
if (!lardon3d_resource_reservation_get_active(
|
||||||
|
governor,
|
||||||
|
next,
|
||||||
|
&information
|
||||||
|
)) {
|
||||||
|
(void)lardon3d_resource_governor_release(governor, next);
|
||||||
|
task->current_reservation = NULL;
|
||||||
|
finish_locked(
|
||||||
|
task,
|
||||||
|
TASK_FAILED,
|
||||||
|
"Réservation de séquence invalide."
|
||||||
|
);
|
||||||
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
task->current_reservation = next;
|
||||||
|
task->contract = (Lardon3DTaskExecutionContract) {
|
||||||
|
.batch_size = information.batch_size,
|
||||||
|
.memory_bytes = information.memory_bytes,
|
||||||
|
.gpu_memory_bytes = information.gpu_memory_bytes,
|
||||||
|
.cpu_threads = information.cpu_threads,
|
||||||
|
.gpu_slots = information.gpu_slots,
|
||||||
|
.io_slots = information.io_slots,
|
||||||
|
};
|
||||||
|
task->has_contract = true;
|
||||||
|
++task->sequence_count;
|
||||||
|
*out_reservation = next;
|
||||||
|
*out_contract = task->contract;
|
||||||
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
lardon3d_task_sequence_count(const Lardon3DTask *task)
|
||||||
|
{
|
||||||
|
if (!task) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Lardon3DTask *mutable_task = (Lardon3DTask *)task;
|
||||||
|
(void)pthread_mutex_lock(&mutable_task->mutex);
|
||||||
|
unsigned int count = task->sequence_count;
|
||||||
|
(void)pthread_mutex_unlock(&mutable_task->mutex);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
lardon3d_task_set_progress(
|
lardon3d_task_set_progress(
|
||||||
Lardon3DTask *task,
|
Lardon3DTask *task,
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,10 @@ queue_worker(void *context)
|
||||||
"Réservation de ressources invalide."
|
"Réservation de ressources invalide."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
/* La tâche peut avoir libéré et re-réservé via sequence_break pendant
|
||||||
|
* son callback. Dans ce cas la réservation d'origine est déjà libérée
|
||||||
|
* et cet appel est sans effet ; la réservation courante de la tâche a
|
||||||
|
* été libérée par lardon3d_task_start. */
|
||||||
(void)lardon3d_resource_governor_release(
|
(void)lardon3d_resource_governor_release(
|
||||||
queue->governor,
|
queue->governor,
|
||||||
reservation
|
reservation
|
||||||
|
|
|
||||||
392
tests/test_sequential_task.c
Normal file
392
tests/test_sequential_task.c
Normal file
|
|
@ -0,0 +1,392 @@
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <lardon3d/task.h>
|
||||||
|
|
||||||
|
#define CHECK(condition) \
|
||||||
|
do { \
|
||||||
|
if (!(condition)) { \
|
||||||
|
(void)fprintf(stderr, "Échec ligne %d : %s\n", __LINE__, #condition); \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Lardon3DResourceGovernor *governor;
|
||||||
|
Lardon3DResourceReservation *initial_reservation;
|
||||||
|
unsigned int expected_breaks;
|
||||||
|
unsigned int breaks_done;
|
||||||
|
size_t batch_sizes[8];
|
||||||
|
Lardon3DTaskExecutionContract initial_contract;
|
||||||
|
bool got_initial_contract;
|
||||||
|
} SeqContext;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Lardon3DResourceGovernor *governor;
|
||||||
|
} WaitContext;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Lardon3DResourceGovernor *governor;
|
||||||
|
pthread_mutex_t sync_mutex;
|
||||||
|
pthread_cond_t sync_cond;
|
||||||
|
bool about_to_break;
|
||||||
|
bool cancel_ready;
|
||||||
|
} CancelContext;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Lardon3DTask *task;
|
||||||
|
Lardon3DResourceGovernor *governor;
|
||||||
|
Lardon3DResourceReservation *reservation;
|
||||||
|
} StartContext;
|
||||||
|
|
||||||
|
static void
|
||||||
|
short_pause(long nanoseconds)
|
||||||
|
{
|
||||||
|
struct timespec duration = {.tv_sec = 0, .tv_nsec = nanoseconds};
|
||||||
|
(void)nanosleep(&duration, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
seq_callback(Lardon3DTask *task, void *userdata)
|
||||||
|
{
|
||||||
|
SeqContext *ctx = userdata;
|
||||||
|
if (!lardon3d_task_execution_contract(task, &ctx->initial_contract)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ctx->got_initial_contract = true;
|
||||||
|
Lardon3DResourceReservation *previous = ctx->initial_reservation;
|
||||||
|
for (unsigned int index = 0; index < ctx->expected_breaks; ++index) {
|
||||||
|
if (!lardon3d_task_checkpoint(task)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Vérifier que la réservation précédente est encore valide AVANT le break */
|
||||||
|
if (previous && !lardon3d_resource_governor_reservation_is_valid(
|
||||||
|
ctx->governor,
|
||||||
|
previous
|
||||||
|
)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Lardon3DResourceReservation *reservation = NULL;
|
||||||
|
Lardon3DTaskExecutionContract contract;
|
||||||
|
if (!lardon3d_task_sequence_break(
|
||||||
|
task,
|
||||||
|
ctx->governor,
|
||||||
|
&reservation,
|
||||||
|
&contract
|
||||||
|
)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!lardon3d_resource_governor_reservation_is_valid(
|
||||||
|
ctx->governor,
|
||||||
|
reservation
|
||||||
|
)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ctx->batch_sizes[index] = contract.batch_size;
|
||||||
|
previous = reservation;
|
||||||
|
++ctx->breaks_done;
|
||||||
|
unsigned int progress = (unsigned int)(
|
||||||
|
((index + 1) * 100) / ctx->expected_breaks
|
||||||
|
);
|
||||||
|
if (!lardon3d_task_set_progress(task, progress, "Séquence.")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
short_pause(2000000);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
wait_callback(Lardon3DTask *task, void *userdata)
|
||||||
|
{
|
||||||
|
WaitContext *ctx = userdata;
|
||||||
|
Lardon3DResourceReservation *reservation = NULL;
|
||||||
|
Lardon3DTaskExecutionContract contract;
|
||||||
|
return lardon3d_task_sequence_break(
|
||||||
|
task,
|
||||||
|
ctx->governor,
|
||||||
|
&reservation,
|
||||||
|
&contract
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
cancel_callback(Lardon3DTask *task, void *userdata)
|
||||||
|
{
|
||||||
|
CancelContext *ctx = userdata;
|
||||||
|
if (!lardon3d_task_checkpoint(task)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
(void)pthread_mutex_lock(&ctx->sync_mutex);
|
||||||
|
ctx->about_to_break = true;
|
||||||
|
(void)pthread_cond_broadcast(&ctx->sync_cond);
|
||||||
|
while (!ctx->cancel_ready) {
|
||||||
|
(void)pthread_cond_wait(&ctx->sync_cond, &ctx->sync_mutex);
|
||||||
|
}
|
||||||
|
(void)pthread_mutex_unlock(&ctx->sync_mutex);
|
||||||
|
Lardon3DResourceReservation *reservation = NULL;
|
||||||
|
Lardon3DTaskExecutionContract contract;
|
||||||
|
return lardon3d_task_sequence_break(
|
||||||
|
task,
|
||||||
|
ctx->governor,
|
||||||
|
&reservation,
|
||||||
|
&contract
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
start_task(void *context)
|
||||||
|
{
|
||||||
|
StartContext *start = context;
|
||||||
|
return (void *)(uintptr_t)(lardon3d_task_start(
|
||||||
|
start->task,
|
||||||
|
start->governor,
|
||||||
|
start->reservation
|
||||||
|
) ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
wait_for_state(Lardon3DTask *task, Lardon3DTaskState expected)
|
||||||
|
{
|
||||||
|
for (size_t attempt = 0; attempt < 5000; ++attempt) {
|
||||||
|
Lardon3DTaskSnapshot snapshot;
|
||||||
|
if (!lardon3d_task_snapshot(task, &snapshot)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (snapshot.state == expected) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
short_pause(1000000);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
run_sequential_test(void)
|
||||||
|
{
|
||||||
|
const Lardon3DResourceEstimate estimate = {
|
||||||
|
.memory_bytes_per_item = 1000,
|
||||||
|
.minimum_batch_size = 1,
|
||||||
|
.maximum_batch_size = 1000,
|
||||||
|
.desired_cpu_threads = 1,
|
||||||
|
};
|
||||||
|
Lardon3DHardwareProfile profile = {
|
||||||
|
.logical_cpu_count = 16,
|
||||||
|
.page_size_bytes = 4096,
|
||||||
|
.memory_total_bytes = UINT64_MAX,
|
||||||
|
.cpu_architecture = "test",
|
||||||
|
};
|
||||||
|
Lardon3DResourcePolicy policy = {
|
||||||
|
.maximum_cpu_load_ratio = 1.0,
|
||||||
|
.maximum_io_pressure_avg10 = 100.0,
|
||||||
|
.io_slot_capacity = 1,
|
||||||
|
};
|
||||||
|
Lardon3DResourceGovernor *governor = lardon3d_resource_governor_create(
|
||||||
|
&profile,
|
||||||
|
&policy
|
||||||
|
);
|
||||||
|
CHECK(governor);
|
||||||
|
Lardon3DResourceSnapshot resource_snapshot = {
|
||||||
|
.memory_available_bytes = 20000,
|
||||||
|
.cpu_load_1m = 0.0,
|
||||||
|
};
|
||||||
|
Lardon3DResourceDecision decision;
|
||||||
|
Lardon3DResourceReservation *reservation;
|
||||||
|
CHECK(lardon3d_resource_governor_reserve(
|
||||||
|
governor,
|
||||||
|
&resource_snapshot,
|
||||||
|
&estimate,
|
||||||
|
&decision,
|
||||||
|
&reservation
|
||||||
|
));
|
||||||
|
CHECK(decision.kind == LARDON3D_RESOURCE_START
|
||||||
|
|| decision.kind == LARDON3D_RESOURCE_REDUCE_BATCH);
|
||||||
|
CHECK(decision.batch_size == 20);
|
||||||
|
|
||||||
|
SeqContext ctx = {
|
||||||
|
.governor = governor,
|
||||||
|
.initial_reservation = reservation,
|
||||||
|
.expected_breaks = 3,
|
||||||
|
};
|
||||||
|
Lardon3DTask *task = lardon3d_task_create(
|
||||||
|
"Séquences",
|
||||||
|
&estimate,
|
||||||
|
seq_callback,
|
||||||
|
&ctx
|
||||||
|
);
|
||||||
|
CHECK(task);
|
||||||
|
StartContext start = {task, governor, reservation};
|
||||||
|
pthread_t thread;
|
||||||
|
CHECK(pthread_create(&thread, NULL, start_task, &start) == 0);
|
||||||
|
CHECK(wait_for_state(task, TASK_RUNNING));
|
||||||
|
CHECK(lardon3d_task_join(task));
|
||||||
|
void *thread_result;
|
||||||
|
CHECK(pthread_join(thread, &thread_result) == 0);
|
||||||
|
CHECK((uintptr_t)thread_result == 1);
|
||||||
|
CHECK(ctx.got_initial_contract);
|
||||||
|
CHECK(ctx.breaks_done == 3);
|
||||||
|
CHECK(ctx.initial_contract.batch_size == 20);
|
||||||
|
CHECK(ctx.batch_sizes[0] == 1000);
|
||||||
|
CHECK(ctx.batch_sizes[1] == 1000);
|
||||||
|
CHECK(ctx.batch_sizes[2] == 1000);
|
||||||
|
CHECK(ctx.batch_sizes[0] != ctx.initial_contract.batch_size);
|
||||||
|
CHECK(lardon3d_task_sequence_count(task) == 3);
|
||||||
|
Lardon3DTaskSnapshot snapshot;
|
||||||
|
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
||||||
|
CHECK(snapshot.state == TASK_COMPLETED);
|
||||||
|
CHECK(snapshot.progress == 100);
|
||||||
|
CHECK(lardon3d_resource_governor_reservation_count(governor) == 0);
|
||||||
|
lardon3d_task_destroy(task);
|
||||||
|
lardon3d_resource_governor_destroy(governor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
run_wait_test(void)
|
||||||
|
{
|
||||||
|
const Lardon3DResourceEstimate estimate = {
|
||||||
|
.minimum_batch_size = 1,
|
||||||
|
.maximum_batch_size = 100,
|
||||||
|
.desired_cpu_threads = 1,
|
||||||
|
.desired_io_slots = 1,
|
||||||
|
};
|
||||||
|
Lardon3DHardwareProfile profile = {
|
||||||
|
.logical_cpu_count = 16,
|
||||||
|
.page_size_bytes = 4096,
|
||||||
|
.memory_total_bytes = UINT64_MAX,
|
||||||
|
.cpu_architecture = "test",
|
||||||
|
};
|
||||||
|
Lardon3DResourcePolicy policy = {
|
||||||
|
.maximum_cpu_load_ratio = 1.0,
|
||||||
|
.maximum_io_pressure_avg10 = 0.0,
|
||||||
|
.io_slot_capacity = 1,
|
||||||
|
};
|
||||||
|
Lardon3DResourceGovernor *governor = lardon3d_resource_governor_create(
|
||||||
|
&profile,
|
||||||
|
&policy
|
||||||
|
);
|
||||||
|
CHECK(governor);
|
||||||
|
Lardon3DResourceSnapshot resource_snapshot = {
|
||||||
|
.memory_available_bytes = UINT64_MAX,
|
||||||
|
.cpu_load_1m = 0.0,
|
||||||
|
.io_pressure_known = false,
|
||||||
|
};
|
||||||
|
Lardon3DResourceDecision decision;
|
||||||
|
Lardon3DResourceReservation *reservation;
|
||||||
|
CHECK(lardon3d_resource_governor_reserve(
|
||||||
|
governor,
|
||||||
|
&resource_snapshot,
|
||||||
|
&estimate,
|
||||||
|
&decision,
|
||||||
|
&reservation
|
||||||
|
));
|
||||||
|
WaitContext ctx = {.governor = governor};
|
||||||
|
Lardon3DTask *task = lardon3d_task_create(
|
||||||
|
"Attente",
|
||||||
|
&estimate,
|
||||||
|
wait_callback,
|
||||||
|
&ctx
|
||||||
|
);
|
||||||
|
CHECK(task);
|
||||||
|
CHECK(lardon3d_task_start(task, governor, reservation));
|
||||||
|
Lardon3DTaskSnapshot snapshot;
|
||||||
|
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
||||||
|
CHECK(snapshot.state == TASK_FAILED);
|
||||||
|
CHECK(lardon3d_resource_governor_reservation_count(governor) == 0);
|
||||||
|
lardon3d_task_destroy(task);
|
||||||
|
lardon3d_resource_governor_destroy(governor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
run_cancel_test(void)
|
||||||
|
{
|
||||||
|
const Lardon3DResourceEstimate estimate = {
|
||||||
|
.minimum_batch_size = 1,
|
||||||
|
.maximum_batch_size = 100,
|
||||||
|
.desired_cpu_threads = 1,
|
||||||
|
};
|
||||||
|
Lardon3DHardwareProfile profile = {
|
||||||
|
.logical_cpu_count = 16,
|
||||||
|
.page_size_bytes = 4096,
|
||||||
|
.memory_total_bytes = UINT64_MAX,
|
||||||
|
.cpu_architecture = "test",
|
||||||
|
};
|
||||||
|
Lardon3DResourcePolicy policy = {
|
||||||
|
.maximum_cpu_load_ratio = 1.0,
|
||||||
|
.maximum_io_pressure_avg10 = 100.0,
|
||||||
|
.io_slot_capacity = 1,
|
||||||
|
};
|
||||||
|
Lardon3DResourceGovernor *governor = lardon3d_resource_governor_create(
|
||||||
|
&profile,
|
||||||
|
&policy
|
||||||
|
);
|
||||||
|
CHECK(governor);
|
||||||
|
Lardon3DResourceSnapshot resource_snapshot = {
|
||||||
|
.memory_available_bytes = UINT64_MAX,
|
||||||
|
.cpu_load_1m = 0.0,
|
||||||
|
};
|
||||||
|
Lardon3DResourceDecision decision;
|
||||||
|
Lardon3DResourceReservation *reservation;
|
||||||
|
CHECK(lardon3d_resource_governor_reserve(
|
||||||
|
governor,
|
||||||
|
&resource_snapshot,
|
||||||
|
&estimate,
|
||||||
|
&decision,
|
||||||
|
&reservation
|
||||||
|
));
|
||||||
|
CancelContext ctx = {.governor = governor};
|
||||||
|
CHECK(pthread_mutex_init(&ctx.sync_mutex, NULL) == 0);
|
||||||
|
CHECK(pthread_cond_init(&ctx.sync_cond, NULL) == 0);
|
||||||
|
Lardon3DTask *task = lardon3d_task_create(
|
||||||
|
"Annulation",
|
||||||
|
&estimate,
|
||||||
|
cancel_callback,
|
||||||
|
&ctx
|
||||||
|
);
|
||||||
|
CHECK(task);
|
||||||
|
StartContext start = {task, governor, reservation};
|
||||||
|
pthread_t thread;
|
||||||
|
CHECK(pthread_create(&thread, NULL, start_task, &start) == 0);
|
||||||
|
(void)pthread_mutex_lock(&ctx.sync_mutex);
|
||||||
|
while (!ctx.about_to_break) {
|
||||||
|
(void)pthread_cond_wait(&ctx.sync_cond, &ctx.sync_mutex);
|
||||||
|
}
|
||||||
|
(void)pthread_mutex_unlock(&ctx.sync_mutex);
|
||||||
|
lardon3d_task_request_cancel(task);
|
||||||
|
(void)pthread_mutex_lock(&ctx.sync_mutex);
|
||||||
|
ctx.cancel_ready = true;
|
||||||
|
(void)pthread_cond_broadcast(&ctx.sync_cond);
|
||||||
|
(void)pthread_mutex_unlock(&ctx.sync_mutex);
|
||||||
|
CHECK(lardon3d_task_join(task));
|
||||||
|
CHECK(pthread_join(thread, NULL) == 0);
|
||||||
|
Lardon3DTaskSnapshot snapshot;
|
||||||
|
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
||||||
|
CHECK(snapshot.state == TASK_CANCELLED);
|
||||||
|
CHECK(lardon3d_resource_governor_reservation_count(governor) == 0);
|
||||||
|
lardon3d_task_destroy(task);
|
||||||
|
(void)pthread_cond_destroy(&ctx.sync_cond);
|
||||||
|
(void)pthread_mutex_destroy(&ctx.sync_mutex);
|
||||||
|
lardon3d_resource_governor_destroy(governor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
if (!run_sequential_test()) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (!run_wait_test()) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (!run_cancel_test()) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
@ -157,7 +157,7 @@ run_test(void)
|
||||||
void *thread_result;
|
void *thread_result;
|
||||||
CHECK(pthread_join(thread, &thread_result) == 0);
|
CHECK(pthread_join(thread, &thread_result) == 0);
|
||||||
CHECK((uintptr_t)thread_result == 1);
|
CHECK((uintptr_t)thread_result == 1);
|
||||||
CHECK(lardon3d_resource_governor_release(governor, reservation));
|
CHECK(!lardon3d_resource_governor_release(governor, reservation));
|
||||||
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
||||||
CHECK(snapshot.state == TASK_COMPLETED);
|
CHECK(snapshot.state == TASK_COMPLETED);
|
||||||
CHECK(snapshot.progress == 100);
|
CHECK(snapshot.progress == 100);
|
||||||
|
|
@ -178,7 +178,7 @@ run_test(void)
|
||||||
lardon3d_task_request_cancel(task);
|
lardon3d_task_request_cancel(task);
|
||||||
CHECK(lardon3d_task_join(task));
|
CHECK(lardon3d_task_join(task));
|
||||||
CHECK(pthread_join(thread, NULL) == 0);
|
CHECK(pthread_join(thread, NULL) == 0);
|
||||||
CHECK(lardon3d_resource_governor_release(governor, reservation));
|
CHECK(!lardon3d_resource_governor_release(governor, reservation));
|
||||||
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
||||||
CHECK(snapshot.state == TASK_CANCELLED);
|
CHECK(snapshot.state == TASK_CANCELLED);
|
||||||
CHECK(snapshot.progress < 100);
|
CHECK(snapshot.progress < 100);
|
||||||
|
|
@ -190,7 +190,7 @@ run_test(void)
|
||||||
governor, &resource_snapshot, &estimate, &decision, &reservation
|
governor, &resource_snapshot, &estimate, &decision, &reservation
|
||||||
));
|
));
|
||||||
CHECK(lardon3d_task_start(task, governor, reservation));
|
CHECK(lardon3d_task_start(task, governor, reservation));
|
||||||
CHECK(lardon3d_resource_governor_release(governor, reservation));
|
CHECK(!lardon3d_resource_governor_release(governor, reservation));
|
||||||
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
||||||
CHECK(snapshot.state == TASK_FAILED);
|
CHECK(snapshot.state == TASK_FAILED);
|
||||||
CHECK(strcmp(snapshot.message, "Erreur contrôlée.") == 0);
|
CHECK(strcmp(snapshot.message, "Erreur contrôlée.") == 0);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue