baobab-ai-dev-core 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. baobab_ai_dev_core-1.0.0/LICENSE +21 -0
  2. baobab_ai_dev_core-1.0.0/PKG-INFO +152 -0
  3. baobab_ai_dev_core-1.0.0/README.md +127 -0
  4. baobab_ai_dev_core-1.0.0/pyproject.toml +92 -0
  5. baobab_ai_dev_core-1.0.0/setup.cfg +4 -0
  6. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/__init__.py +27 -0
  7. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/__init__.py +5 -0
  8. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/__init__.py +13 -0
  9. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/ai_provider.py +134 -0
  10. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/artifact.py +91 -0
  11. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/backlog.py +171 -0
  12. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/blocker.py +110 -0
  13. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/feature.py +114 -0
  14. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/job.py +215 -0
  15. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/project.py +157 -0
  16. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/pull_request.py +85 -0
  17. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/quality_check.py +137 -0
  18. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/user_story.py +114 -0
  19. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/workflow_run.py +275 -0
  20. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/entities/workflow_step.py +252 -0
  21. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/__init__.py +35 -0
  22. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/ai_provider_status.py +18 -0
  23. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/ai_provider_type.py +16 -0
  24. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/artifact_type.py +12 -0
  25. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/blocker_severity.py +16 -0
  26. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/branch_type.py +16 -0
  27. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/job_status.py +19 -0
  28. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/merge_decision.py +14 -0
  29. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/project_status.py +16 -0
  30. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/pull_request_status.py +12 -0
  31. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/quality_check_status.py +18 -0
  32. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/quality_check_type.py +15 -0
  33. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/quality_gate_status.py +14 -0
  34. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/work_item_status.py +20 -0
  35. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/workflow_run_status.py +19 -0
  36. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/enums/workflow_step_status.py +19 -0
  37. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/exceptions/__init__.py +41 -0
  38. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/exceptions/baobab_ai_dev_core_error.py +14 -0
  39. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/exceptions/domain_validation_error.py +17 -0
  40. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/exceptions/hierarchy_violation_error.py +13 -0
  41. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/exceptions/invalid_branch_name_error.py +13 -0
  42. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/exceptions/invalid_identifier_error.py +15 -0
  43. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/exceptions/invalid_status_transition_error.py +14 -0
  44. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/exceptions/merge_not_allowed_error.py +13 -0
  45. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/exceptions/provider_unavailable_error.py +13 -0
  46. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/exceptions/quality_gate_failed_error.py +13 -0
  47. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/policies/__init__.py +7 -0
  48. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/policies/branch_policy.py +93 -0
  49. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/policies/merge_eligibility_policy.py +91 -0
  50. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/policies/provider_fallback_policy.py +40 -0
  51. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/policies/pull_request_target_policy.py +51 -0
  52. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/policies/quality_gate_policy.py +45 -0
  53. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/policies/status_transition_policy.py +159 -0
  54. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/policies/work_item_hierarchy_policy.py +159 -0
  55. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/protocols/__init__.py +1 -0
  56. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/protocols/ai_provider_protocol.py +25 -0
  57. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/protocols/backlog_repository_protocol.py +31 -0
  58. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/protocols/clock_protocol.py +17 -0
  59. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/protocols/feature_repository_protocol.py +31 -0
  60. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/protocols/git_client_protocol.py +37 -0
  61. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/protocols/project_repository_protocol.py +36 -0
  62. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/protocols/pull_request_client_protocol.py +38 -0
  63. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/protocols/quality_check_repository_protocol.py +31 -0
  64. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/protocols/quality_runner_protocol.py +21 -0
  65. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/protocols/user_story_repository_protocol.py +31 -0
  66. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/protocols/workflow_run_repository_protocol.py +31 -0
  67. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/value_objects/__init__.py +23 -0
  68. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/value_objects/backlog_code.py +38 -0
  69. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/value_objects/branch_name.py +115 -0
  70. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/value_objects/domain_description.py +39 -0
  71. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/value_objects/domain_title.py +35 -0
  72. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/value_objects/entity_id.py +39 -0
  73. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/value_objects/feature_code.py +38 -0
  74. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/value_objects/project_slug.py +34 -0
  75. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/value_objects/semantic_version.py +58 -0
  76. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/domain/value_objects/user_story_code.py +38 -0
  77. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core/py.typed +0 -0
  78. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core.egg-info/PKG-INFO +152 -0
  79. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core.egg-info/SOURCES.txt +79 -0
  80. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core.egg-info/dependency_links.txt +1 -0
  81. baobab_ai_dev_core-1.0.0/src/baobab_ai_dev_core.egg-info/top_level.txt +1 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 baobabgit
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,152 @@
1
+ Metadata-Version: 2.4
2
+ Name: baobab-ai-dev-core
3
+ Version: 1.0.0
4
+ Summary: Noyau métier Python pur de l'écosystème baobab-ai-development : entités, objets de valeur, enums, exceptions, politiques et contrats partagés.
5
+ Author-email: Michel ANDRIANAIVO <patrick.andri@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/baobabgit/baobab-ai-dev-core
8
+ Project-URL: Repository, https://github.com/baobabgit/baobab-ai-dev-core.git
9
+ Keywords: baobab,domain,core,workflow,ai-development
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Topic :: Software Development :: Libraries
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.12
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Dynamic: license-file
25
+
26
+ # baobab-ai-dev-core
27
+
28
+ Noyau métier Python pur de l'écosystème **baobab-ai-development**.
29
+
30
+ Ce module centralise le vocabulaire et les règles métier partagés par les modules
31
+ d'infrastructure : `database`, `documents`, `git`, `quality`, `providers`, `workflow`,
32
+ `API`, `CLI` et `workers`. Il ne réalise aucune I/O (réseau, disque, base de données) :
33
+ il modélise le domaine, valide les invariants et publie des contrats (`Protocol`) que
34
+ les adaptateurs externes implémentent.
35
+
36
+ ## Rôle du module
37
+
38
+ `baobab-ai-dev-core` fournit :
39
+
40
+ - **Entités** — `Project`, `UserStory`, `Feature`, `Backlog`, `WorkflowRun`,
41
+ `WorkflowStep`, `Job`, `AiProvider`, `Blocker`, `Artifact`, `QualityCheck`,
42
+ `PullRequest`
43
+ - **Objets de valeur** — identifiants, codes métier (`US-XXX`, `FEAT-XXX`, `BL-XXX`),
44
+ noms de branches, titres, versions sémantiques
45
+ - **Enums** — statuts, types, sévérités et décisions stables du domaine
46
+ - **Exceptions** — hiérarchie `BaobabAiDevCoreError` avec messages exploitables
47
+ - **Politiques** — règles pures sans I/O (transitions, hiérarchie, branches, merge,
48
+ quality gate, fallback provider)
49
+ - **Contrats `Protocol`** — repositories et clients Git, PR, qualité, providers IA,
50
+ horloge injectable
51
+
52
+ Le workflow documentaire **US → FEAT → BL** et la hiérarchie Git **`main` → `us/*` →
53
+ `feat/*` → `bl/*`** sont modélisés et validables dans ce noyau.
54
+
55
+ ## Non-objectifs
56
+
57
+ Ce package **n'implémente pas** :
58
+
59
+ - API HTTP (FastAPI, etc.)
60
+ - Persistance SQL (SQLAlchemy, Alembic)
61
+ - Appels Git ou GitHub réels
62
+ - Exécution de providers IA (Cursor, Claude, GPT, Codex, etc.)
63
+ - Runners qualité réels, parsing Markdown, file de jobs persistée, CLI
64
+
65
+ Ces responsabilités appartiennent aux modules consommateurs qui implémentent les
66
+ `Protocol` du domaine.
67
+
68
+ ## Prérequis
69
+
70
+ - Python **>= 3.12**
71
+ - Dépendances runtime : **aucune** (bibliothèque standard uniquement)
72
+
73
+ ## Installation locale (développement)
74
+
75
+ Depuis la racine du dépôt :
76
+
77
+ ```bash
78
+ python -m pip install -e .
79
+ ```
80
+
81
+ Vérifier que le package est importable :
82
+
83
+ ```bash
84
+ python -c "import baobab_ai_dev_core; print(baobab_ai_dev_core.__version__)"
85
+ ```
86
+
87
+ ## Premiers imports
88
+
89
+ ### API publique stabilisée
90
+
91
+ Les consommateurs doivent importer depuis le package racine. Seuls les symboles listés
92
+ dans `__all__` constituent le contrat public stable :
93
+
94
+ ```python
95
+ import baobab_ai_dev_core
96
+
97
+ print(baobab_ai_dev_core.__version__) # "1.0.0"
98
+ print(baobab_ai_dev_core.__all__) # ["__version__"]
99
+ ```
100
+
101
+ ```python
102
+ from baobab_ai_dev_core import __version__
103
+
104
+ assert __version__ == "1.0.0"
105
+ ```
106
+
107
+ Tout symbole absent de `__all__` est considéré **interne** et peut évoluer sans
108
+ préavis. Les ré-exportations publiques des briques domaine seront étendues au fur et à
109
+ mesure de leur stabilisation.
110
+
111
+ ### Accès aux briques domaine (usage interne écosystème)
112
+
113
+ En attendant l'élargissement de `__all__`, les modules de l'écosystème importent les
114
+ sous-packages du domaine avec des **imports absolus** :
115
+
116
+ ```python
117
+ from baobab_ai_dev_core.domain.entities.project import Project
118
+ from baobab_ai_dev_core.domain.value_objects.entity_id import EntityId
119
+ from baobab_ai_dev_core.domain.value_objects.project_slug import ProjectSlug
120
+ from baobab_ai_dev_core.domain.enums.project_status import ProjectStatus
121
+ from baobab_ai_dev_core.domain.policies.branch_policy import BranchPolicy
122
+ from baobab_ai_dev_core.domain.protocols.git_client_protocol import GitClientProtocol
123
+ ```
124
+
125
+ Ne pas importer depuis des chemins relatifs ; ne pas dépendre de symboles non exportés
126
+ via `__all__` pour une API tierce.
127
+
128
+ ## Arborescence du domaine
129
+
130
+ ```text
131
+ src/baobab_ai_dev_core/domain/
132
+ entities/ # entités avec identité et transitions explicites
133
+ value_objects/ # objets immuables validés à la création
134
+ enums/ # vocabulaires stables
135
+ exceptions/ # erreurs métier
136
+ policies/ # règles pures sans I/O
137
+ protocols/ # contrats pour l'infrastructure
138
+ ```
139
+
140
+ Les tests unitaires miroirs vivent sous `tests/baobab_ai_dev_core/domain/`.
141
+
142
+ ## Commandes qualité
143
+
144
+ ```bash
145
+ python -m pytest
146
+ python -m ruff check .
147
+ python -m mypy src
148
+ ```
149
+
150
+ ## Licence
151
+
152
+ MIT — voir [LICENSE](LICENSE).
@@ -0,0 +1,127 @@
1
+ # baobab-ai-dev-core
2
+
3
+ Noyau métier Python pur de l'écosystème **baobab-ai-development**.
4
+
5
+ Ce module centralise le vocabulaire et les règles métier partagés par les modules
6
+ d'infrastructure : `database`, `documents`, `git`, `quality`, `providers`, `workflow`,
7
+ `API`, `CLI` et `workers`. Il ne réalise aucune I/O (réseau, disque, base de données) :
8
+ il modélise le domaine, valide les invariants et publie des contrats (`Protocol`) que
9
+ les adaptateurs externes implémentent.
10
+
11
+ ## Rôle du module
12
+
13
+ `baobab-ai-dev-core` fournit :
14
+
15
+ - **Entités** — `Project`, `UserStory`, `Feature`, `Backlog`, `WorkflowRun`,
16
+ `WorkflowStep`, `Job`, `AiProvider`, `Blocker`, `Artifact`, `QualityCheck`,
17
+ `PullRequest`
18
+ - **Objets de valeur** — identifiants, codes métier (`US-XXX`, `FEAT-XXX`, `BL-XXX`),
19
+ noms de branches, titres, versions sémantiques
20
+ - **Enums** — statuts, types, sévérités et décisions stables du domaine
21
+ - **Exceptions** — hiérarchie `BaobabAiDevCoreError` avec messages exploitables
22
+ - **Politiques** — règles pures sans I/O (transitions, hiérarchie, branches, merge,
23
+ quality gate, fallback provider)
24
+ - **Contrats `Protocol`** — repositories et clients Git, PR, qualité, providers IA,
25
+ horloge injectable
26
+
27
+ Le workflow documentaire **US → FEAT → BL** et la hiérarchie Git **`main` → `us/*` →
28
+ `feat/*` → `bl/*`** sont modélisés et validables dans ce noyau.
29
+
30
+ ## Non-objectifs
31
+
32
+ Ce package **n'implémente pas** :
33
+
34
+ - API HTTP (FastAPI, etc.)
35
+ - Persistance SQL (SQLAlchemy, Alembic)
36
+ - Appels Git ou GitHub réels
37
+ - Exécution de providers IA (Cursor, Claude, GPT, Codex, etc.)
38
+ - Runners qualité réels, parsing Markdown, file de jobs persistée, CLI
39
+
40
+ Ces responsabilités appartiennent aux modules consommateurs qui implémentent les
41
+ `Protocol` du domaine.
42
+
43
+ ## Prérequis
44
+
45
+ - Python **>= 3.12**
46
+ - Dépendances runtime : **aucune** (bibliothèque standard uniquement)
47
+
48
+ ## Installation locale (développement)
49
+
50
+ Depuis la racine du dépôt :
51
+
52
+ ```bash
53
+ python -m pip install -e .
54
+ ```
55
+
56
+ Vérifier que le package est importable :
57
+
58
+ ```bash
59
+ python -c "import baobab_ai_dev_core; print(baobab_ai_dev_core.__version__)"
60
+ ```
61
+
62
+ ## Premiers imports
63
+
64
+ ### API publique stabilisée
65
+
66
+ Les consommateurs doivent importer depuis le package racine. Seuls les symboles listés
67
+ dans `__all__` constituent le contrat public stable :
68
+
69
+ ```python
70
+ import baobab_ai_dev_core
71
+
72
+ print(baobab_ai_dev_core.__version__) # "1.0.0"
73
+ print(baobab_ai_dev_core.__all__) # ["__version__"]
74
+ ```
75
+
76
+ ```python
77
+ from baobab_ai_dev_core import __version__
78
+
79
+ assert __version__ == "1.0.0"
80
+ ```
81
+
82
+ Tout symbole absent de `__all__` est considéré **interne** et peut évoluer sans
83
+ préavis. Les ré-exportations publiques des briques domaine seront étendues au fur et à
84
+ mesure de leur stabilisation.
85
+
86
+ ### Accès aux briques domaine (usage interne écosystème)
87
+
88
+ En attendant l'élargissement de `__all__`, les modules de l'écosystème importent les
89
+ sous-packages du domaine avec des **imports absolus** :
90
+
91
+ ```python
92
+ from baobab_ai_dev_core.domain.entities.project import Project
93
+ from baobab_ai_dev_core.domain.value_objects.entity_id import EntityId
94
+ from baobab_ai_dev_core.domain.value_objects.project_slug import ProjectSlug
95
+ from baobab_ai_dev_core.domain.enums.project_status import ProjectStatus
96
+ from baobab_ai_dev_core.domain.policies.branch_policy import BranchPolicy
97
+ from baobab_ai_dev_core.domain.protocols.git_client_protocol import GitClientProtocol
98
+ ```
99
+
100
+ Ne pas importer depuis des chemins relatifs ; ne pas dépendre de symboles non exportés
101
+ via `__all__` pour une API tierce.
102
+
103
+ ## Arborescence du domaine
104
+
105
+ ```text
106
+ src/baobab_ai_dev_core/domain/
107
+ entities/ # entités avec identité et transitions explicites
108
+ value_objects/ # objets immuables validés à la création
109
+ enums/ # vocabulaires stables
110
+ exceptions/ # erreurs métier
111
+ policies/ # règles pures sans I/O
112
+ protocols/ # contrats pour l'infrastructure
113
+ ```
114
+
115
+ Les tests unitaires miroirs vivent sous `tests/baobab_ai_dev_core/domain/`.
116
+
117
+ ## Commandes qualité
118
+
119
+ ```bash
120
+ python -m pytest
121
+ python -m ruff check .
122
+ python -m mypy src
123
+ ```
124
+
125
+ ## Licence
126
+
127
+ MIT — voir [LICENSE](LICENSE).
@@ -0,0 +1,92 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "baobab-ai-dev-core"
7
+ version = "1.0.0"
8
+ description = "Noyau métier Python pur de l'écosystème baobab-ai-development : entités, objets de valeur, enums, exceptions, politiques et contrats partagés."
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Michel ANDRIANAIVO", email = "patrick.andri@gmail.com" }]
14
+ keywords = ["baobab", "domain", "core", "workflow", "ai-development"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Programming Language :: Python :: 3 :: Only",
24
+ "Topic :: Software Development :: Libraries",
25
+ "Topic :: Software Development :: Libraries :: Python Modules",
26
+ "Typing :: Typed",
27
+ ]
28
+ dependencies = []
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/baobabgit/baobab-ai-dev-core"
32
+ Repository = "https://github.com/baobabgit/baobab-ai-dev-core.git"
33
+
34
+ [tool.setuptools.packages.find]
35
+ where = ["src"]
36
+
37
+ [tool.setuptools.package-data]
38
+ baobab_ai_dev_core = ["py.typed"]
39
+
40
+ [tool.pytest.ini_options]
41
+ minversion = "8.0"
42
+ testpaths = ["tests"]
43
+ pythonpath = ["src"]
44
+ addopts = "-ra --strict-markers --strict-config"
45
+
46
+ [tool.ruff]
47
+ line-length = 100
48
+ target-version = "py312"
49
+ src = ["src", "tests"]
50
+
51
+ [tool.ruff.lint]
52
+ select = [
53
+ "E", # pycodestyle errors
54
+ "W", # pycodestyle warnings
55
+ "F", # pyflakes
56
+ "I", # isort
57
+ "N", # pep8-naming
58
+ "UP", # pyupgrade
59
+ "B", # flake8-bugbear
60
+ "C4", # flake8-comprehensions
61
+ "SIM", # flake8-simplify
62
+ "PT", # flake8-pytest-style
63
+ "TID", # flake8-tidy-imports
64
+ "ANN", # flake8-annotations
65
+ "D", # pydocstyle
66
+ "PL", # pylint
67
+ "RUF", # ruff-specific
68
+ ]
69
+ ignore = [
70
+ # D401 impose le « mode impératif » selon une heuristique anglophone,
71
+ # incompatible avec la convention de docstrings en français du projet.
72
+ "D401",
73
+ ]
74
+
75
+ [tool.ruff.lint.pydocstyle]
76
+ convention = "pep257"
77
+
78
+ [tool.ruff.lint.flake8-tidy-imports]
79
+ ban-relative-imports = "all"
80
+
81
+ [tool.ruff.lint.per-file-ignores]
82
+ "tests/**/*.py" = ["D101", "D102", "D103", "PLR2004"]
83
+
84
+ [tool.mypy]
85
+ python_version = "3.12"
86
+ strict = true
87
+ warn_unused_configs = true
88
+ warn_redundant_casts = true
89
+ warn_unused_ignores = true
90
+ disallow_any_generics = true
91
+ no_implicit_reexport = true
92
+ show_error_codes = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,27 @@
1
+ """baobab-ai-dev-core — noyau métier Python pur de l'écosystème baobab-ai-development.
2
+
3
+ Ce package expose les briques de domaine (entités, objets de valeur, enums,
4
+ exceptions, politiques et contrats ``Protocol``) consommées par les modules
5
+ database, documents, git, quality, providers, workflow, API, CLI et workers.
6
+
7
+ Convention d'API publique
8
+ --------------------------
9
+ - Point d'entrée unique : les consommateurs importent depuis ``baobab_ai_dev_core``
10
+ (``from baobab_ai_dev_core import ...``), jamais depuis les sous-modules internes.
11
+ - Contrat explicite : seuls les symboles listés dans :data:`__all__` font partie de
12
+ l'API publique stable. Tout symbole absent de ``__all__`` est considéré interne et
13
+ peut changer sans préavis.
14
+ - Compatibilité : ``__all__`` est maintenu trié pour limiter les diffs et garantir un
15
+ ordre déterministe. Les sous-packages du domaine (``domain.entities``,
16
+ ``domain.enums``, ``domain.value_objects``, ``domain.policies``,
17
+ ``domain.protocols``, ``domain.exceptions``) y seront re-exportés au fur et à mesure
18
+ de leur stabilisation dans les user stories suivantes.
19
+
20
+ À ce stade, seul le numéro de version est exposé publiquement via ``__all__``.
21
+ """
22
+
23
+ __version__ = "1.0.0"
24
+
25
+ __all__ = [
26
+ "__version__",
27
+ ]
@@ -0,0 +1,5 @@
1
+ """Sous-package domaine de baobab-ai-dev-core.
2
+
3
+ Regroupe les briques métier pures : ``entities``, ``value_objects``, ``enums``,
4
+ ``exceptions``, ``policies`` et ``protocols``.
5
+ """
@@ -0,0 +1,13 @@
1
+ """Entités métier du domaine baobab-ai-dev-core."""
2
+
3
+ from baobab_ai_dev_core.domain.entities.backlog import Backlog
4
+ from baobab_ai_dev_core.domain.entities.feature import Feature
5
+ from baobab_ai_dev_core.domain.entities.project import Project
6
+ from baobab_ai_dev_core.domain.entities.user_story import UserStory
7
+
8
+ __all__ = [
9
+ "Backlog",
10
+ "Feature",
11
+ "Project",
12
+ "UserStory",
13
+ ]
@@ -0,0 +1,134 @@
1
+ """Entité métier représentant un provider IA au niveau domaine."""
2
+
3
+ from baobab_ai_dev_core.domain.enums.ai_provider_status import AiProviderStatus
4
+ from baobab_ai_dev_core.domain.enums.ai_provider_type import AiProviderType
5
+ from baobab_ai_dev_core.domain.exceptions.domain_validation_error import (
6
+ DomainValidationError,
7
+ )
8
+ from baobab_ai_dev_core.domain.value_objects.domain_title import DomainTitle
9
+ from baobab_ai_dev_core.domain.value_objects.entity_id import EntityId
10
+
11
+ _PRIORITE_MIN = 1
12
+ _QUOTA_OK = "ok"
13
+ _QUOTA_EXHAUSTED = "usage_exhausted"
14
+
15
+
16
+ def _valider_priorite(priorite: int) -> int:
17
+ if priorite < _PRIORITE_MIN:
18
+ raise DomainValidationError(
19
+ f"La priorité doit être >= {_PRIORITE_MIN} (reçue : {priorite})."
20
+ )
21
+ return priorite
22
+
23
+
24
+ def _valider_quota_state(quota_state: str) -> str:
25
+ nettoye = quota_state.strip()
26
+ if nettoye not in {_QUOTA_OK, _QUOTA_EXHAUSTED}:
27
+ raise DomainValidationError(
28
+ f"quota_state invalide : '{quota_state}'. "
29
+ f"Valeurs attendues : '{_QUOTA_OK}', '{_QUOTA_EXHAUSTED}'."
30
+ )
31
+ return nettoye
32
+
33
+
34
+ def _valider_coherence_statut_quota(
35
+ status: AiProviderStatus,
36
+ quota_state: str,
37
+ ) -> None:
38
+ """Vérifie l'alignement entre statut et quota."""
39
+ if status is AiProviderStatus.USAGE_EXHAUSTED and quota_state != _QUOTA_EXHAUSTED:
40
+ raise DomainValidationError(
41
+ "Le statut 'usage_exhausted' exige quota_state='usage_exhausted'."
42
+ )
43
+ if status is AiProviderStatus.AVAILABLE and quota_state != _QUOTA_OK:
44
+ raise DomainValidationError(
45
+ "Le statut 'available' exige quota_state='ok'."
46
+ )
47
+
48
+
49
+ class AiProvider:
50
+ """Provider IA métier avec priorité, statut et état de quota.
51
+
52
+ Ne contient aucun client technique : l'intégration relève du module
53
+ ``providers``.
54
+ """
55
+
56
+ def __init__( # noqa: PLR0913
57
+ self,
58
+ provider_id: EntityId,
59
+ name: DomainTitle,
60
+ provider_type: AiProviderType,
61
+ status: AiProviderStatus,
62
+ priority: int,
63
+ quota_state: str,
64
+ ) -> None:
65
+ """Construit un provider en validant priorité et quota."""
66
+ priorite = _valider_priorite(priority)
67
+ quota = _valider_quota_state(quota_state)
68
+ _valider_coherence_statut_quota(status, quota)
69
+ self._provider_id = provider_id
70
+ self._name = name
71
+ self._provider_type = provider_type
72
+ self._status = status
73
+ self._priority = priorite
74
+ self._quota_state = quota
75
+
76
+ @property
77
+ def provider_id(self) -> EntityId:
78
+ """Identifiant stable du provider."""
79
+ return self._provider_id
80
+
81
+ @property
82
+ def name(self) -> DomainTitle:
83
+ """Nom affiché du provider."""
84
+ return self._name
85
+
86
+ @property
87
+ def provider_type(self) -> AiProviderType:
88
+ """Famille technique du provider."""
89
+ return self._provider_type
90
+
91
+ @property
92
+ def status(self) -> AiProviderStatus:
93
+ """Statut de disponibilité courant."""
94
+ return self._status
95
+
96
+ @property
97
+ def priority(self) -> int:
98
+ """Priorité de sélection (1 = la plus haute)."""
99
+ return self._priority
100
+
101
+ @property
102
+ def quota_state(self) -> str:
103
+ """État du quota (``ok`` ou ``usage_exhausted``)."""
104
+ return self._quota_state
105
+
106
+ @property
107
+ def is_selectable(self) -> bool:
108
+ """Indique si le provider peut être sélectionné pour un run."""
109
+ return (
110
+ self._status is AiProviderStatus.AVAILABLE
111
+ and self._quota_state == _QUOTA_OK
112
+ )
113
+
114
+ def mark_usage_exhausted(self) -> None:
115
+ """Marque le quota comme épuisé (distinct de indisponible ou erreur)."""
116
+ self._status = AiProviderStatus.USAGE_EXHAUSTED
117
+ self._quota_state = _QUOTA_EXHAUSTED
118
+
119
+ def mark_error(self) -> None:
120
+ """Marque une erreur technique sans confondre avec quota épuisé."""
121
+ self._status = AiProviderStatus.ERROR
122
+
123
+ def disable(self) -> None:
124
+ """Désactive volontairement le provider."""
125
+ self._status = AiProviderStatus.DISABLED
126
+
127
+ def mark_unavailable(self) -> None:
128
+ """Marque une indisponibilité ponctuelle."""
129
+ self._status = AiProviderStatus.UNAVAILABLE
130
+
131
+ def restore_available(self) -> None:
132
+ """Restaure un provider disponible avec quota OK."""
133
+ self._status = AiProviderStatus.AVAILABLE
134
+ self._quota_state = _QUOTA_OK
@@ -0,0 +1,91 @@
1
+ """Entité métier représentant un livrable produit pendant une exécution."""
2
+
3
+ import re
4
+ from datetime import datetime
5
+
6
+ from baobab_ai_dev_core.domain.enums.artifact_type import ArtifactType
7
+ from baobab_ai_dev_core.domain.exceptions.domain_validation_error import (
8
+ DomainValidationError,
9
+ )
10
+ from baobab_ai_dev_core.domain.value_objects.entity_id import EntityId
11
+
12
+ _CHEMIN_RELATIF_PATTERN = re.compile(r"^[a-zA-Z0-9_./-]+$")
13
+
14
+
15
+ def _valider_chemin(path: str) -> str:
16
+ nettoye = path.strip()
17
+ if not nettoye:
18
+ raise DomainValidationError("Le chemin d'artefact ne peut pas être vide.")
19
+ if nettoye.startswith("/") or ".." in nettoye.split("/"):
20
+ raise DomainValidationError(
21
+ f"Le chemin '{nettoye}' doit être relatif et ne pas contenir '..'."
22
+ )
23
+ if not _CHEMIN_RELATIF_PATTERN.fullmatch(nettoye):
24
+ raise DomainValidationError(
25
+ f"Le chemin '{nettoye}' contient des caractères non autorisés."
26
+ )
27
+ return nettoye
28
+
29
+
30
+ def _valider_checksum(checksum: str | None) -> str | None:
31
+ if checksum is None:
32
+ return None
33
+ nettoye = checksum.strip()
34
+ if not nettoye:
35
+ raise DomainValidationError(
36
+ "Le checksum ne peut pas être vide lorsqu'il est renseigné."
37
+ )
38
+ return nettoye
39
+
40
+
41
+ class Artifact:
42
+ """Livrable généré pendant un workflow run (patch, rapport, fichier, etc.)."""
43
+
44
+ def __init__( # noqa: PLR0913
45
+ self,
46
+ artifact_id: EntityId,
47
+ workflow_run_id: EntityId,
48
+ artifact_type: ArtifactType,
49
+ path: str,
50
+ checksum: str | None,
51
+ created_at: datetime,
52
+ ) -> None:
53
+ """Construit un artefact en validant le chemin relatif et le checksum."""
54
+ chemin = _valider_chemin(path)
55
+ empreinte = _valider_checksum(checksum)
56
+ self._artifact_id = artifact_id
57
+ self._workflow_run_id = workflow_run_id
58
+ self._artifact_type = artifact_type
59
+ self._path = chemin
60
+ self._checksum = empreinte
61
+ self._created_at = created_at
62
+
63
+ @property
64
+ def artifact_id(self) -> EntityId:
65
+ """Identifiant stable de l'artefact."""
66
+ return self._artifact_id
67
+
68
+ @property
69
+ def workflow_run_id(self) -> EntityId:
70
+ """Identifiant du run ayant produit l'artefact."""
71
+ return self._workflow_run_id
72
+
73
+ @property
74
+ def artifact_type(self) -> ArtifactType:
75
+ """Type métier de l'artefact."""
76
+ return self._artifact_type
77
+
78
+ @property
79
+ def path(self) -> str:
80
+ """Chemin relatif validé de l'artefact."""
81
+ return self._path
82
+
83
+ @property
84
+ def checksum(self) -> str | None:
85
+ """Empreinte facultative du contenu."""
86
+ return self._checksum
87
+
88
+ @property
89
+ def created_at(self) -> datetime:
90
+ """Horodatage de création."""
91
+ return self._created_at