Effort Estimator
1. Quoi ? — Definition et contexte
Section intitulée « 1. Quoi ? — Definition et contexte »L’Effort Estimator est une famille de quatre workflows N8N qui repondent a une question recurrente : combien d’heures pour cette tache ? Pas d’appel LLM, pas de devinette : un calcul deterministe base sur les taches deja terminees dans Odoo, dont on connait a la fois l’estimation initiale et le temps reel passe.
Le principe est simple. Chaque tache Odoo accumule un champ x_estimated_hours (estimation manuelle ou heuristique) et un total d’heures reelles, agregees depuis les timesheets (account.analytic.line) ou les sessions Claude Code. Une fois assez d’echantillons apparies, on extrait des centiles (P25 / P50 / P75) sur une cohorte similaire et on les renvoie comme estimation low / likely / high.
Les quatre workflows de la famille
Section intitulée « Les quatre workflows de la famille »| Workflow | ID | Nodes | Role |
|---|---|---|---|
| Estimation Coverage Weekly | BABocZHi7nlZ1uU5 | 9 | Digest hebdomadaire de couverture vers le seuil de 30 echantillons apparies |
| Effort Estimator V1 | 2A03Nc8Co0Blr96m | 9 | Sub-workflow : selection de cohorte + centiles + score de confiance |
| Estimate Handler | ZzB58z0NVIntIDT3 | 7 | Handler de la commande /estimate <description> cote Telegram |
| Odoo Project Picker | TMGWxV5BrVcGht4Z | 10 | Selecteur paginé de projets Odoo (sub-workflow reutilise) |
Donnees mobilisees
Section intitulée « Donnees mobilisees »| Source Odoo | Champs cles | Usage |
|---|---|---|
project.task | x_estimated_hours, x_complexity, x_claude_category, x_github_repo, x_claude_sessions, x_claude_cost_total | Constitue l’echantillon d’apprentissage |
account.analytic.line | task_id, unit_amount | Heures reelles (timesheets) |
project.task.claude.session | task_id, active_time_hours | Fallback : sessions Claude Code pour les taches sans timesheet |
Les taches dites “generic bucket” (x_claude_category defini, agregats par type de commit) sont exclues : elles ne sont pas individuellement estimables.
2. Pourquoi ? — Enjeux et motivations
Section intitulée « 2. Pourquoi ? — Enjeux et motivations »Le besoin
Section intitulée « Le besoin »Sans estimateur, chaque nouvelle issue arrive sans reference. Trois consequences immediates :
| Sans estimateur | Avec Effort Estimator V1 |
|---|---|
| Estimations a la louche, biais d’optimisme | Centiles tires de l’historique, exposes en direct sur Telegram |
| Aucune visibilite sur l’ecart estime / reel | Suivi hebdomadaire de la couverture vers le seuil de 30 apparies |
| Une seule estimation, sans intervalle | Triplet low / likely / high (P25/P50/P75) + confiance |
Pourquoi deterministe et pas LLM ?
Section intitulée « Pourquoi deterministe et pas LLM ? »| Critere | LLM | Deterministe centiles |
|---|---|---|
| Reproductibilite | Variable selon le modele et la temperature | Identique a donnees egales |
| Auditabilite | Boite noire | Cohorte + samples visibles |
| Cout | Token-based, recurrent | Zero |
| Donnee privee | Sort du VPS | Reste interne |
| Qualite avec n < 30 | Acceptable par fluff | Honnete : “low confidence” affichee |
La porte de phase 2 : 30 echantillons apparies
Section intitulée « La porte de phase 2 : 30 echantillons apparies »L’epic #188 prevoit de debloquer un estimateur semantique (matching par description) seulement quand 30 paires (estime, reel) sont disponibles. En dessous, le bruit domine le signal. Le digest Estimation Coverage Weekly materialise cette porte : chaque lundi 09:00 Europe/Paris, un message Telegram montre le nombre courant de paires, le delta semaine sur semaine, et un message “Phase 2 DEBLOQUEE” quand le seuil tombe.
3. Comment ? — Mise en oeuvre technique
Section intitulée « 3. Comment ? — Mise en oeuvre technique »Vue d’ensemble
Section intitulée « Vue d’ensemble »Les trois requetes paralleles d’Effort Estimator V1
Section intitulée « Les trois requetes paralleles d’Effort Estimator V1 »Le sub-workflow 2A03Nc8Co0Blr96m (9 nodes) declenche trois requetes Odoo en parallele, puis un node Merge attend les trois sorties avant de passer au calcul. Ce pattern est partage avec le digest hebdomadaire.
| # | Node | Type | Role |
|---|---|---|---|
| 1 | Execute Workflow Trigger | trigger | Input passthrough : description, project_id?, repo? |
| 2 | Odoo Get Paired Tasks | odoo | project.task getAll, filtre x_estimated_hours != false, exclut generic bucket |
| 3 | Odoo Get Timesheets | odoo | account.analytic.line getAll, unit_amount > 0 |
| 4 | Odoo Get Sessions | odoo | project.task.claude.session getAll, fallback heures Claude Code |
| 5 | Wait All Queries | merge | Combine by position, 3 entrees |
| 6 | Build Estimate | code | Selection cohorte, centiles, score |
| 7 | Has Data? | if | Aiguillage si echantillon vide |
| 8 | Respond (true) | code | Renvoi structure estimee |
| 9 | Respond (false) | code | Renvoi {error: "no_data"} |
La cascade de cohortes
Section intitulée « La cascade de cohortes »Le node Code Build Estimate applique une priorite stricte : il prend la premiere cohorte qui contient au moins 5 echantillons.
| Priorite | Dimension | Source |
|---|---|---|
| 1 | project_id | Parametre d’entree |
| 2 | x_github_repo | Parametre d’entree |
| 3 | x_claude_category | Derivee de la description (matching de mots-cles) |
| 4 | x_complexity | Derivee de la description (longueur + mots-cles) |
| 5 | Global | Tous les echantillons apparies |
La derivation de categorie est volontairement courte : doc/readme → docs, fix/bug/crash → fix, refactor/clean → refactor, etc. Pareil pour la complexite (court + typo/rename → simple, architect/migrat/redesign → complex, defaut medium).
Le score de confiance
Section intitulée « Le score de confiance »Trois facteurs pesent dans un total :
| Facteur | Poids | High (3) | Medium (2) | Low (1) |
|---|---|---|---|---|
| Taille de l’echantillon | 40 % | n >= 20 | n >= 10 | n < 10 |
| Dispersion (IQR / mediane) | 30 % | <= 0.5 | <= 1.0 | > 1.0 |
| Proximite de cohorte | 30 % | project / repo | category / complexity | global |
Le total >= 2.5 = high, >= 1.5 = medium, sinon low. La confiance est toujours retournee a l’appelant : utile pour le Handler Telegram qui ajoute un avertissement quand elle est basse.
Format de sortie
Section intitulée « Format de sortie »{ "has_data": true, "estimated_hours_low": 0.5, "estimated_hours_likely": 1.0, "estimated_hours_high": 3.1, "expected_sessions": 2, "expected_api_cost": 0.31, "sample_size": 34, "confidence": "medium", "based_on": "repo=GuiGPaP/stacks_vps (n=34)"}En absence d’echantillon exploitable, le payload tombe sur {has_data: false, error: "no_data"} et le Handler renvoie un message d’usage plutot qu’un faux chiffre.
Le parcours /estimate depuis Telegram
Section intitulée « Le parcours /estimate depuis Telegram »Le Estimate Handler (ZzB58z0NVIntIDT3, 7 nodes) recoit deux types d’entrees, deja extraites par l’Orchestrateur Telegram :
| Source | Format d’entree |
|---|---|
Commande /estimate <description> | Texte brut, parse pour retirer le prefixe |
| Bouton menu “Estimer” + ForceReply | Reponse libre du Reply Action Handler |
Le node Extract Description valide la presence d’un texte non vide, puis appelle l’Effort Estimator V1. Le retour est mis en forme HTML pour Telegram :
Effort Estimate
Add pagination to /todo digest
Low Likely High0.5 1.0 3.1(hours)
Sessions: ~2 | API cost: ~$0.31Based on: 34 tasks (repo=GuiGPaP/stacks_vps (n=34))Confidence: mediumLe digest hebdomadaire
Section intitulée « Le digest hebdomadaire »Le Estimation Coverage Weekly (BABocZHi7nlZ1uU5, 9 nodes) tourne via un Schedule Trigger calé sur lundi 09:00 Europe/Paris. Son objectif est de tracker la progression vers la porte de phase 2.
| # | Node | Role |
|---|---|---|
| 1 | Schedule Trigger | Cron lundi 09:00 |
| 2 | Odoo Get Tasks | project.task getAll (limit 500), champs estimation + telemetrie |
| 3 | Odoo Get Timesheets | account.analytic.line getAll (limit 2000) |
| 4 | DT Get Previous Report | Lecture de la derniere ligne pour calcul de delta |
| 5 | Wait All Queries | Merge des 3 entrees |
| 6 | Build Coverage Report | Jointure + metriques + formatage HTML |
| 7 | Has Data? | Skip si aucune tache active |
| 8 | Call Notification Hub | type=digest, severity=info |
| 9 | DT Save Snapshot | INSERT dans estimation_coverage_history |
La Data Table estimation_coverage_history (yBggBMumLMqfzQbv) conserve un snapshot par semaine : report_date, total_tasks, estimated_count, paired_count, gate_ready. Le delta affiche dans le message Telegram ([+3], [+2]) sort directement de cette table.
Et l’Odoo Project Picker ?
Section intitulée « Et l’Odoo Project Picker ? »Le quatrieme workflow, Odoo Project Picker (TMGWxV5BrVcGht4Z, 10 nodes), est un selecteur paginé generique. Ce n’est pas un composant strict de l’estimation, mais il est branchable au Handler quand l’utilisateur veut une estimation cantonnee a un projet precis : /estimate ouvre alors une vue paginée Telegram, l’utilisateur tape sur un projet, et le project_id selectionne est injecte dans l’appel V1. Il est partage avec les routes /projet status et la pagination de listes Odoo.
4. Et si ? — Perspectives et limites
Section intitulée « 4. Et si ? — Perspectives et limites »Limites actuelles
Section intitulée « Limites actuelles »| Limite | Impact | Mitigation |
|---|---|---|
| Faible volume d’echantillons | En dessous de 30 paires, la confiance reste basse | Digest hebdomadaire surveille la progression |
| Matching par mot-cle | Categorisation grossiere | Phase 2 prevoit un matching semantique |
| Pas d’apprentissage en ligne | Pas de mise a jour incrementale par execution | Acceptable, les centiles sont stables |
| Cohorte globale en fallback | Une grosse tache peut tirer la mediane vers le haut | La dispersion abaisse la confiance |
Scenarios d’evolution
Section intitulée « Scenarios d’evolution »Si la couverture franchit 30 paires :
- Activation de la phase 2 : matching semantique sur le titre + corps via embeddings
- Comparaison automatique avec l’estimation manuelle au moment de l’ouverture d’issue
- Affichage de tasks “voisines” dans le message Telegram pour comparaison
Si le volume explose :
- Indexation par projet pour eviter le full scan
limit=500 - Cache des cohortes en Redis avec invalidation a chaque cloture
- Pre-calcul des centiles dans une table de stats Odoo
Si plusieurs utilisateurs :
- Cohorte additionnelle par contributeur (utile pour personnaliser l’estimation)
- Possibilite de filtrer les samples sur sa propre velocite
- Calibration interactive (re-estimer une tache passee via Telegram)
Pages liees
Section intitulée « Pages liees »Workflows
Section intitulée « Workflows »- Claude Code Telemetry — Alimente
x_claude_sessions,x_claude_cost_totalet le fallbackproject.task.claude.session - GitHub-Odoo Sync — Fournit le pipeline d’issues GitHub vers
project.task(champsx_estimated_hours,x_complexity) - Digests & Triage Quotidien — Famille de digests reguliers dont Estimation Coverage Weekly fait partie
Infrastructure
Section intitulée « Infrastructure »- Odoo 18 sur Docker — Module
project_github_syncet champsx_*
Reference
Section intitulée « Reference »- Glossaire — Centile, IQR, sub-workflow