Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f954cc19d1 | |||
| 97d3b64780 | |||
| 3ff51d94fb | |||
| d2ab269684 | |||
| 68f8c1a718 | |||
| 59eb4dcb7c | |||
| 4f390b4ee2 | |||
| dcb463ee00 | |||
| 49123ecba3 | |||
| 1c0cb8e973 | |||
| bd3572b382 | |||
| 576e78b6a9 | |||
| 8dcedb092c | |||
| cb8d931abb | |||
| 2e71c5f51e | |||
| 2bc3afbd1a | |||
| 519f6dbfee | |||
| 4841b77099 | |||
| 0752e35988 | |||
| 3cb1bf06e1 | |||
| ca15e7e12b | |||
| 448c310398 | |||
| ccb86fe7ca | |||
| 0f4f1b533b | |||
| 655eeeb4a1 | |||
| 335d449346 | |||
| 215c9e6f25 | |||
| 0d4fd0942c | |||
| 11c48b668b | |||
| bcfc0f9a9d | |||
| 03b481c6ee | |||
| ab73cf9384 | |||
| d429fccf9a | |||
| aab89a6032 | |||
| bf11db6d85 | |||
| 40ee6f6a46 | |||
| a5de76b7c1 | |||
| 87c88beaa2 | |||
| 1485e4d6ac | |||
| 7e674f2f09 | |||
| 15812c1dff | |||
| a40bfc51c1 | |||
| 64b635073a | |||
| d20d37607d | |||
| d587b446b9 | |||
| f91a22f458 | |||
| 17c3d2b104 | |||
| 18a758045f | |||
| 861260462f | |||
| 47ef210910 |
@@ -25,7 +25,7 @@ Livrer une plateforme intégrée BIM + ERPNext + Console luxury + OTOIA orchestr
|
||||
- **Speckle** : bim-cloud.otov7.com (viewer 3D)
|
||||
- **Design system** : `#0a0a12` dark + `#f0b429` doré · Fraunces + Cormorant Garamond
|
||||
|
||||
## Tes 12 agents spécialisés (voir `03_agents/`)
|
||||
## Tes 13 agents spécialisés (voir `03_agents/`)
|
||||
Chaque agent a son propre `AGENT.md` avec scope + outils + non-négociables.
|
||||
|
||||
## Ton livrable final (semaine 8)
|
||||
|
||||
@@ -71,7 +71,7 @@ auto-générée en **< 1h** (le BIM alimente le volet Ingénierie + les vues).
|
||||
|
||||
## Communication inter-agents
|
||||
- Rapports quotidiens dans `05_deliverables_mvp/daily_reports/`
|
||||
- Handoffs formalisés dans `05_deliverables_mvp/handoffs/`
|
||||
- Hand-off inter-agents = livrables déterministes commités in-repo (fixtures/specs `out/`, SPEC, README), consommés directement par l'agent destinataire
|
||||
- Blockers escalés à Michel Roy via WhatsApp +18296296385
|
||||
|
||||
## Éthique
|
||||
|
||||
@@ -65,7 +65,7 @@ P05 client).
|
||||
|
||||
## Communication inter-agents
|
||||
- Rapports quotidiens dans `05_deliverables_mvp/daily_reports/`
|
||||
- Handoffs formalisés dans `05_deliverables_mvp/handoffs/`
|
||||
- Hand-off inter-agents = livrables déterministes commités in-repo (fixtures/specs `out/`, SPEC, README), consommés directement par l'agent destinataire
|
||||
- Blockers escalés à Michel Roy via WhatsApp +18296296385
|
||||
|
||||
## Éthique
|
||||
|
||||
@@ -23,6 +23,20 @@ et vérifications HTTP restent côté **agent DevOps/ERPNext Backend**.
|
||||
|---|---|---|---|---|
|
||||
| [`.gitea/workflows/ci.yml`](../../.gitea/workflows/ci.yml) + [`ci/`](../../ci/README.md) | 1 (roadmap L29) | **CI/CD Gitea Actions** : 3 guards blocants (contraintes / JSON / docs) + un job de tests par livrable gated + `gate` agrégateur + `e2e-baseline` | déclenché sur `push`/`pull_request` → `main` + `workflow_dispatch` | 22 suites gated |
|
||||
| [`05_deliverables_mvp/devops/deploy_runbook/`](../../05_deliverables_mvp/devops/deploy_runbook/README.md) | 8 (roadmap L73) | **Run-book VPS unifié** : graphe de **7 phases ordonnées** couvrant TOUS les modules gated, dépendances inter-phases + confirmations préalables sourcées | `deploy_runbook_gen.py build\|validate` | 29 (dont 14 injections négatives) |
|
||||
| [`run_ci.sh`](../../run_ci.sh) | 8 (roadmap L73 · « regression exhaustifs ») | **Miroir LOCAL du gate** : rejoue en une commande, hors runner et hors réseau, l'ensemble exact des checks de `gate.needs` | `bash run_ci.sh` (outil, non un gate) | — (voir ci-dessous) |
|
||||
|
||||
### `run_ci.sh` — outillage local, PAS un gate (#5)
|
||||
Confort développeur, pas un maillon de la chaîne de merge : le script **dérive**
|
||||
sa liste de checks de `gate.needs` (`.gitea/workflows/ci.yml`, la source déjà
|
||||
verrouillée par `ci/check_ci_integrity.sh`) — **zéro liste en dur**, donc aucune
|
||||
dérive silencieuse possible (ajouter/retirer un job CI se répercute ici sans
|
||||
édition). Il n'ajoute **aucun `ci/*.sh` ni aucune assertion** : ce n'est **pas**
|
||||
un gate (CLAUDE.md #5), il ne s'inscrit pas dans `gate.needs` et, la racine
|
||||
n'étant pas sous `ci/`, il échappe par construction à l'invariant qui interdit un
|
||||
`ci/*.sh` non câblé au gate. Périmètre = uniquement les jobs de `gate.needs`
|
||||
(exclut les jobs `workflow_dispatch` type `e2e-baseline`/`npm test` qui exigent
|
||||
Node). Le décompte jobs/gates/suites est **imprimé à l'exécution** — jamais figé
|
||||
dans le code, où il se périmerait (anti-invention · #6).
|
||||
|
||||
### Le gate CI — trois guards blocants (`ci/`)
|
||||
- **`guard_constraints.sh`** : détecte l'**usage** (pas la simple mention) des
|
||||
@@ -89,7 +103,7 @@ Voir `04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md`. Volets DevOps : Sprint 1 (repo Git
|
||||
|
||||
## Communication inter-agents
|
||||
- Rapports quotidiens dans `05_deliverables_mvp/daily_reports/`
|
||||
- Handoffs formalisés dans `05_deliverables_mvp/handoffs/`
|
||||
- Hand-off inter-agents = livrables déterministes commités in-repo (fixtures/specs `out/`, SPEC, README), consommés directement par l'agent destinataire
|
||||
- Blockers escalés à Michel Roy via WhatsApp +18296296385
|
||||
|
||||
## Éthique
|
||||
|
||||
@@ -84,7 +84,7 @@ L51) · Sprint 6 (Chat OTOIA embedded dans chaque portail · L63).
|
||||
|
||||
## Communication inter-agents
|
||||
- Rapports quotidiens dans `05_deliverables_mvp/daily_reports/`
|
||||
- Handoffs formalisés dans `05_deliverables_mvp/handoffs/`
|
||||
- Hand-off inter-agents = livrables déterministes commités in-repo (fixtures/specs `out/`, SPEC, README), consommés directement par l'agent destinataire
|
||||
- Blockers escalés à Michel Roy via WhatsApp +18296296385
|
||||
|
||||
## Éthique
|
||||
|
||||
@@ -29,6 +29,12 @@ le générateur, son contrat et ses fixtures d'entrée le sont (le rendu réel d
|
||||
s'exécute côté OTOIA/VPS · #8).
|
||||
|
||||
## Sources canoniques
|
||||
> **Chemins VPS runtime — hors périmètre worker (#8), non commités in-repo** (préfixe
|
||||
> absolu `/opt/oto/…`, placeholder de version `{X}`). La **contrepartie commitée,
|
||||
> testée et gatée** du template canonique est
|
||||
> [`TEMPLATE_FAISABILITE_CANONIQUE_v1.0.md`](../../05_deliverables_mvp/faisabilite/TEMPLATE_FAISABILITE_CANONIQUE_v1.0.md)
|
||||
> (table §Livrables ci-dessus) — **la référence de vérité pour le worker** ; les
|
||||
> chemins ci-dessous décrivent l'emplacement runtime OTOIA/VPS où l'agent exécute.
|
||||
- `/opt/oto/otoia/capabilities/knowledge/faisabilite_4_volets_standard.md` (STANDARD OFFICIEL)
|
||||
- `/opt/oto/data_room/_TEMPLATE_FAISABILITE_v{X}/` (template versionné)
|
||||
- `/opt/oto/data_room/PXX/00_brief/` (données projet)
|
||||
|
||||
@@ -104,7 +104,7 @@ directement le montage des Workspaces (réutilisation `wslib`) — coordination.
|
||||
|
||||
## Communication inter-agents
|
||||
- Rapports quotidiens dans `05_deliverables_mvp/daily_reports/`
|
||||
- Handoffs formalisés dans `05_deliverables_mvp/handoffs/`
|
||||
- Hand-off inter-agents = livrables déterministes commités in-repo (fixtures/specs `out/`, SPEC, README), consommés directement par l'agent destinataire
|
||||
- Blockers escalés à Michel Roy via WhatsApp +18296296385
|
||||
|
||||
## Éthique
|
||||
|
||||
@@ -89,7 +89,7 @@ modèle publié sur `bim-cloud.otov7.com` et affiché dans le viewer console.
|
||||
|
||||
## Communication inter-agents
|
||||
- Rapports quotidiens dans `05_deliverables_mvp/daily_reports/`
|
||||
- Handoffs formalisés dans `05_deliverables_mvp/handoffs/`
|
||||
- Hand-off inter-agents = livrables déterministes commités in-repo (fixtures/specs `out/`, SPEC, README), consommés directement par l'agent destinataire
|
||||
- Blockers escalés à Michel Roy via WhatsApp +18296296385
|
||||
|
||||
## Éthique
|
||||
|
||||
@@ -101,7 +101,7 @@ modules RBAC + API + Expo 54 en place, builds/submissions ~**50 %**.
|
||||
|
||||
## Communication inter-agents
|
||||
- Rapports quotidiens dans `05_deliverables_mvp/daily_reports/`
|
||||
- Handoffs formalisés dans `05_deliverables_mvp/handoffs/`
|
||||
- Hand-off inter-agents = livrables déterministes commités in-repo (fixtures/specs `out/`, SPEC, README), consommés directement par l'agent destinataire
|
||||
- Blockers escalés à Michel Roy via WhatsApp +18296296385
|
||||
|
||||
## Éthique
|
||||
|
||||
@@ -114,7 +114,7 @@ attribués roadmap à **QA** (`qa/audit_5d/`) — coordination ci-dessous.
|
||||
|
||||
## Communication inter-agents
|
||||
- Rapports quotidiens dans `05_deliverables_mvp/daily_reports/`
|
||||
- Handoffs formalisés dans `05_deliverables_mvp/handoffs/`
|
||||
- Hand-off inter-agents = livrables déterministes commités in-repo (fixtures/specs `out/`, SPEC, README), consommés directement par l'agent destinataire
|
||||
- Blockers escalés à Michel Roy via WhatsApp +18296296385
|
||||
|
||||
## Éthique
|
||||
|
||||
+23
-1
@@ -36,6 +36,28 @@ périmètre — un auditeur ne s'audite jamais.
|
||||
Ce compte est **découvert automatiquement depuis le CI** (`q4lib.registry.parse_ci`,
|
||||
réutilisé sans duplication) — jamais compté à la main.
|
||||
|
||||
## Deuxième étage QA : la batterie de gates statiques (`ci/*.sh`)
|
||||
Au-dessus des 4 modules d'audit ci-dessus, le mandat exécute une couche de **gates
|
||||
statiques** — les *gates de méta-niveau* du titre. Leur périmètre n'est **jamais**
|
||||
figé à la main : `check_ci_integrity` **découvre** l'ensemble via `git ls-files
|
||||
'ci/*.sh'` et **refuse** qu'un `ci/*.sh` ne soit pas câblé à un job du gate CI (ou
|
||||
inversement) — la liste ci-dessous est donc *l'état courant*, pas une constante.
|
||||
|
||||
| Gate | Rôle (une commande, déterministe, zéro chiffre fabriqué) |
|
||||
|---|---|
|
||||
| `check_ci_integrity.sh` | Intégrité du câblage CI : chaque `ci/*.sh` est câblé à un job **dans** `gate.needs` (aucun gate décâblé ni orphelin) — c'est le gardien des gardiens (il **s'exclut** lui-même · SoD). |
|
||||
| `check_readme_claims.sh` | Intégrité des **chiffres** des README / fiches agent (CLAUDE.md #6) : chaque compte cité est **recalculé** depuis l'artefact `out/` ou la source (jamais une donnée inventée). |
|
||||
| `check_artifacts.sh` | **Reproductibilité** : chaque `out/*.json` se régénère **byte-identique** (aucune dérive entre source et hand-off commité). |
|
||||
| `check_regression.sh` | **Fraîcheur** de la matrice de régression : le run rejoué == le run commité (aucune régression silencieuse · #5). |
|
||||
| `check_docs.sh` | Qualité documentaire : les liens Markdown relatifs internes pointent vers une cible **existante** (gate 4Big). |
|
||||
| `guard_constraints.sh` | Enforce les **contraintes NON-NÉGOCIABLES** de CLAUDE.md : plateformes git proscrites (hors Gitea), CRM interdits, paiement non conforme, écriture serveur bannie — via une prohibition marquée ou l'échappatoire `ci-allow`. |
|
||||
| `validate_json.sh` | Tous les `.json` suivis sont **bien formés** (parse strict) — première ligne de défense avant toute lecture d'artefact. |
|
||||
|
||||
Ces gates ne **produisent** pas de livrable métier : ils **prouvent** que les
|
||||
livrables des autres agents tiennent. Un nouveau gate suit la même règle — il est
|
||||
**automatiquement** intégré au périmètre dès qu'il est câblé (découverte CI), sans
|
||||
liste à maintenir.
|
||||
|
||||
## Non-négociables (voir CLAUDE.md racine pour la liste complète)
|
||||
- Gitea only (jamais GitHub)
|
||||
- ERPNext natif en priorité
|
||||
@@ -61,7 +83,7 @@ ISA/IFRS) · Sprint 7 (audit 4Big 95+/100 sur 100 % deliverables) · Sprint 8
|
||||
|
||||
## Communication inter-agents
|
||||
- Rapports quotidiens dans `05_deliverables_mvp/daily_reports/`
|
||||
- Handoffs formalisés dans `05_deliverables_mvp/handoffs/`
|
||||
- Hand-off inter-agents = livrables déterministes commités in-repo (fixtures/specs `out/`, SPEC, README), consommés directement par l'agent destinataire
|
||||
- Blockers escalés à Michel Roy via WhatsApp +18296296385
|
||||
|
||||
## Coordination inter-agents
|
||||
|
||||
@@ -103,7 +103,7 @@ sprint mesurable : **P07 Aqua Terra** — faisabilité 4 volets auto-générée
|
||||
|
||||
## Communication inter-agents
|
||||
- Rapports quotidiens dans `05_deliverables_mvp/daily_reports/`
|
||||
- Handoffs formalisés dans `05_deliverables_mvp/handoffs/`
|
||||
- Hand-off inter-agents = livrables déterministes commités in-repo (fixtures/specs `out/`, SPEC, README), consommés directement par l'agent destinataire
|
||||
- Blockers escalés à Michel Roy via WhatsApp +18296296385
|
||||
|
||||
## Éthique
|
||||
|
||||
@@ -75,7 +75,7 @@ hreflang »).
|
||||
|
||||
## Communication inter-agents
|
||||
- Rapports quotidiens dans `05_deliverables_mvp/daily_reports/`
|
||||
- Handoffs formalisés dans `05_deliverables_mvp/handoffs/`
|
||||
- Hand-off inter-agents = livrables déterministes commités in-repo (fixtures/specs `out/`, SPEC, README), consommés directement par l'agent destinataire
|
||||
- Blockers escalés à Michel Roy via WhatsApp +18296296385
|
||||
|
||||
## Éthique
|
||||
|
||||
@@ -1,5 +1,186 @@
|
||||
# Activity Log · 2026-08-01 · Claude Code DTP
|
||||
|
||||
## Session `20260801_230453` · Buffer S8 · QA/Audit 5D : gate d'IDENTITÉ du **VERDICT GLOBAL** — le LABEL de conclusion de l'audit
|
||||
|
||||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||||
complète ; la valeur marginale reste le durcissement anti-dérive (CLAUDE.md #6)
|
||||
des surfaces prose data-derived encore non gatées. Les 7 gates verts au départ.
|
||||
|
||||
**Surface trouvée (aveugle)** : le **verdict global** de l'audit 5D — le LABEL
|
||||
`PASS` / `PASS_WITH_OPEN_ITEMS` / `FAIL` qui est la **HEADLINE de tout le
|
||||
livrable** — était **HORS de tout gate**. Le bloc audit_5d existant recompute la
|
||||
**ventilation chiffrée** (« **13 PASS · 0 FAIL · 4 à confirmer** », pass/fail/à
|
||||
confirmer d'`audit_report.totals`), l'énumération des open items, les 5 dimensions
|
||||
et les livrables audités — mais **jamais le label de verdict lui-même**. Or ce
|
||||
label est data-derived (`out/audit_report.json[verdict]` == `out/MANIFEST.json[verdict]`
|
||||
== `PASS_WITH_OPEN_ITEMS`, byte-gatés), recalculé par `qalib/builder.py` via la
|
||||
règle **`FAIL` si ≥1 FAIL · sinon `PASS_WITH_OPEN_ITEMS` si ≥1 A_CONFIRMER · sinon
|
||||
`PASS`**, et transcrit à la main à **deux** endroits du README : la RÈGLE
|
||||
(`Verdict global : …`, l.39) et le VERDICT COURANT (`## Verdict courant` l.49). Le
|
||||
risque #6 est le **CŒUR** du livrable : écrire `PASS` alors que 4 params
|
||||
réglementaires restent `a_confirmer` = l'audit « force » un PASS et prétend propre
|
||||
un dossier qui ne l'est pas — exactement ce que l'audit reproche aux autres. La
|
||||
ventilation chiffrée peut rester exacte pendant que le label ment ; ni
|
||||
`check_artifacts` (byte only) ni les suites `tests/` (FONCTIONS, pas la prose)
|
||||
n'attrapent.
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Audit 5D · IDENTITÉ du VERDICT
|
||||
GLOBAL », inséré juste après la ventilation chiffrée) : on **MIROITE** la règle du
|
||||
générateur et on exige — **(a)** HONNÊTETÉ interne : `audit_report.verdict` ==
|
||||
verdict recalculé du triplet (fail>0→FAIL · a_confirmer>0→PASS_WITH_OPEN_ITEMS ·
|
||||
sinon PASS) ⇒ un verdict FORCÉ incohérent avec ses propres chiffres est mordu ;
|
||||
**(b)** CROISÉ : `MANIFEST.verdict` == `audit_report.verdict` ; **(c)** le LABEL
|
||||
« Verdict courant » du README == `audit_report.verdict` (ancré sur le heading +
|
||||
la ventilation `**N PASS`, pas sur la règle l.39) ; **(d)** la RÈGLE « Verdict
|
||||
global » énumère EXACTEMENT le **codomaine** `{FAIL, PASS_WITH_OPEN_ITEMS, PASS}`
|
||||
du générateur (un label renommé côté `builder.py` sans mise à jour de la règle est
|
||||
mordu). Claim absent = échec (disparition = régression).
|
||||
|
||||
**5 morsures vérifiées** (working tree byte-restauré après chacune via
|
||||
`git checkout -- <chemin précis>`, JAMAIS `git checkout .` / `git clean`) :
|
||||
1. README label `PASS_WITH_OPEN_ITEMS`→`PASS` → ✗ (c) « Verdict courant = PASS MAIS
|
||||
artefact PASS_WITH_OPEN_ITEMS » ;
|
||||
2. README règle l.39 `PASS_WITH_OPEN_ITEMS`→`PASS_OPEN` → ✗ (d) « codomaine
|
||||
[FAIL, PASS, PASS_OPEN] ≠ [FAIL, PASS, PASS_WITH_OPEN_ITEMS] » ;
|
||||
3. `audit_report.verdict`→`PASS` (à_confirmer reste 4) → ✗ (a) « verdict FORCÉ,
|
||||
incohérent — viole #6 » **+** cascade ✗ (b) + ✗ (c) (3 fails : l'honnêteté est
|
||||
la morsure la plus forte) ;
|
||||
4. `MANIFEST.verdict`→`PASS` → ✗ (b) « MANIFEST PASS MAIS audit_report
|
||||
PASS_WITH_OPEN_ITEMS (désynchronisés) » ;
|
||||
5. README label supprimé (l.49) → ✗ (c) « Verdict courant INTROUVABLE ».
|
||||
Restauré = green : (a)(b)(c)(d) tous ✓.
|
||||
|
||||
- `ci/README.md` : la sous-clause « audit 5D » de la row `check-readme-claims`
|
||||
étendue de l'IDENTITÉ du VERDICT GLOBAL (label + honnêteté interne + croisé
|
||||
MANIFEST + codomaine de la règle documentée).
|
||||
- **7 gates re-verts** : `guard_constraints` / `validate_json` / `check_docs` /
|
||||
`check_artifacts` / `check_regression` / `check_ci_integrity` /
|
||||
`check_readme_claims` (tous rc=0).
|
||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
## Session `20260801_210434` · Buffer S8 · Domaine CRM/commissions : l'**IDENTITÉ du CHAMP DEVISE** — la clause `devise_field` = le champ `devise` (`Select` **USD/DOP** · #10) du DocType Dossier Vente, transcrite **en prose** dans la §« Cross-cohérence » (`crm/commissions/README.md:54`) — était **HORS de tout gate**. Les trois blocs commissions déjà en place gatent les états soumis / brouillons exclus, les champs de base Currency, l'identité des rôles payés (portail `ventes`) et la promesse anti-taux #6 — mais **aucun** ne touchait ce couple champ↔devises (l'**invariant CLI #8** du générateur).
|
||||
|
||||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). **4e surface distincte du
|
||||
MÊME livrable `crm/commissions`** (après états/champs, anti-taux, rôles payés) — le
|
||||
« **sur quelle devise** » du calcul `base × taux`. Surface DISTINCTE du bloc « Fiches
|
||||
#10 » (prose ERPNext/CRM) et du bloc e-CF `TipoMoneda` (options du spec fiscal) :
|
||||
ici c'est le champ `devise` du DocType Dossier Vente + la clé racine `devise_field`
|
||||
du plan, ancrés sur **CLAUDE.md #10** (« **USD + DOP** devises »).
|
||||
|
||||
**Dérive silencieuse fermée** :
|
||||
- `05_deliverables_mvp/crm/commissions/README.md:54` — clause « `devise_field` = le
|
||||
champ `devise` (`Select` **USD/DOP** · #10) du DocType » : NOMME le champ (`devise`),
|
||||
son fieldtype (`Select`), ses options (`USD/DOP`) et tague `#10`.
|
||||
- Sources faisant autorité : (a) `out/commission_plan.json` (byte-gaté par
|
||||
`check_artifacts`) — clé RACINE `devise_field` (le champ du Dossier Vente qui porte
|
||||
la devise d'un montant commissionné) ; (b) `crm/dossier_vente/doctype_spec.json`
|
||||
(l'INPUT du générateur) — le champ `devise` de fieldtype `Select` + ses `options` ;
|
||||
(c) **CLAUDE.md #10** (ligne 24 : « **USD + DOP** devises ») — les 2 devises
|
||||
canoniques. L'invariant CLI #8 (`commissions_gen.py:151-158`) exige les trois
|
||||
simultanément ; le gate re-dérive INDÉPENDAMMENT.
|
||||
- Piège : la seule vérification existante (`tests/`) teste des **FONCTIONS**
|
||||
finance/résolution, jamais la PROSE vs l'artefact. RENOMMER le champ (`devise`→
|
||||
`moneda`), changer son fieldtype (`Select`→`Data` : énumération PERDUE, montant en
|
||||
monnaie libre) ou altérer ses options (`USD/DOP`→`USD/EUR` : devise HORS #10 → le
|
||||
calcul commissionnerait dans une monnaie non prévue) laisse la prose périmée EN
|
||||
SILENCE. `devise_field` n'apparaissait NULLE PART dans `ci/` (grep = 0).
|
||||
- **État courant** : **aucune valeur périmée** — `plan.devise_field == "devise"` ==
|
||||
champ DocType `devise` (`Select`, options `[USD, DOP]`) == CLAUDE.md #10 ; la prose
|
||||
README recoupe tout exactement (anti-invention #6, rien à réécrire). Le défaut est
|
||||
la **surface ungated**.
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « CRM/Commissions ·
|
||||
IDENTITÉ du CHAMP DEVISE » après le bloc rôles payés) : (0) **ANCRAGE** — les 2
|
||||
devises depuis le segment gras « USD + DOP » de CLAUDE.md #10 ; (a) **CROSS-ARTEFACT**
|
||||
— `plan.devise_field == "devise"` == fieldname du champ DocType, fieldtype `Select`,
|
||||
`options` (ORDRE inclus) == devises #10 ; (b) **PROSE** — README:54 nomme le champ
|
||||
`devise`, le dit `Select`, cite `USD/DOP` == #10 et tague `#10`. Un claim absent
|
||||
échoue AUSSI (traçabilité #6). Direction plan/DocType/#10 → README.
|
||||
|
||||
**7 morsures vérifiées** (4 côté README · 1 DocType · 1 CLAUDE.md · 1 plan) : README
|
||||
champ `devise→moneda` (prose périmée) · README `Select→Data` (type périmé) · README
|
||||
`USD/DOP→USD/EUR` (devises périmées) · README tag `· #10` retiré (claim INTROUVABLE) ·
|
||||
**DocType** `options USD→EUR` (hors #10, cross-artefact) · **CLAUDE.md #10**
|
||||
`USD+DOP→USD+EUR` (ancrage VIVANT · mord le cross-artefact) · **plan** `devise_field
|
||||
devise→moneda` (invariant #8) ; restauré = green : plan.devise_field == DocType ==
|
||||
#10 · prose == artefacts · exit 0. Working tree byte-restauré (`git checkout --`,
|
||||
**JAMAIS** `git clean`, interdit absolu) · **7 gates re-verts**
|
||||
(`check_readme_claims`/`check_ci_integrity`/`check_docs`/`guard_constraints`/
|
||||
`check_artifacts`/`check_regression`/`validate_json`).
|
||||
|
||||
- `ci/README.md` (clause de la table récap du pipeline + paragraphe détaillé
|
||||
« Quatrième surface du MÊME livrable `crm/commissions` · identité du champ devise »)
|
||||
mis à jour.
|
||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; la création du
|
||||
champ `devise` du DocType `bench` reste côté VPS).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
## Session `20260801_183412` · Buffer S8 · Domaine Legal/CONFOTUR : les **deux champs du DocType `CONFOTUR Application` DÉRIVÉS du pipeline vente** — `dossier_vente` (Link → cible `workflow.document_type` = `OTO Dossier Vente`) et `estado` (Select → options = les états `confotur_*` du **workflow vente**), transcrits **en prose** dans la §« Cœur du livrable : cross-cohérence » (`legal/confotur/README.md:33-36`) — étaient **HORS de tout gate d'IDENTITÉ**. Les blocs CONFOTUR amont gatent le **compte** de champs/rôles, la cross-cohérence des **PERMISSIONS** (rôle→actions) et l'ancrage des **ENTITÉS** (`entite_porteuse`→CLAUDE.md §Entités) — mais **aucun** ne touchait `dossier_vente`/`estado`.
|
||||
|
||||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). **Même classe EXACTE** que
|
||||
l'ancrage `entite_porteuse` du MÊME README (session `20260801` entités CONFOTUR) —
|
||||
appliqué à la **surface distincte** des deux AUTRES champs data-derived du même
|
||||
DocType, jamais gatés hors comptes/permissions/entités.
|
||||
|
||||
**Dérive silencieuse fermée** :
|
||||
- `05_deliverables_mvp/legal/confotur/README.md:35-36` — bullet `dossier_vente`
|
||||
(Link) : « cible = `workflow.document_type` (= `OTO Dossier Vente`) » (valeur
|
||||
NOMMÉE en clair) · `:33-34` — bullet `estado` (Select) : « options = les états
|
||||
`confotur_*` du **workflow vente** … dérivées — jamais réécrites en dur ».
|
||||
- Source faisant autorité : `crm/workflow_vente/workflow_vente_spec.json` — l'**INPUT**
|
||||
que le builder confotur LIT (déclaré `workflow_source` dans le MANIFEST), d'où il
|
||||
tire `document_type` (= cible du Link) et les `update_value` d'états commençant par
|
||||
`confotur` (= options du Select). L'artefact `out/doctype_confotur_application.json`
|
||||
porte `dossier_vente.options`/`estado.options`, byte-gaté par `check_artifacts`.
|
||||
- Piège : la seule vérification existante (`tests/`) teste des **FONCTIONS** de
|
||||
génération, jamais la PROSE du README. RENOMMER le DocType porteur côté workflow
|
||||
(`OTO Dossier Vente`→`OTO Dossier de Vente`) ou AJOUTER/RENOMMER un état CONFOTUR
|
||||
régénère l'artefact confotur (`check_artifacts` reste VERT — il se reconstruit
|
||||
depuis le spec workflow) MAIS laisse la prose README « (= `OTO Dossier Vente`) »
|
||||
périmée EN SILENCE → l'agent ONAPI/Legal câblerait une cible de Link / un menu
|
||||
d'états que le pipeline ne porte plus (l'invention #6 interdit).
|
||||
- **État courant** : **aucune valeur périmée** — `dossier_vente` Link → « OTO
|
||||
Dossier Vente » == workflow `document_type` · `estado` options
|
||||
`[confotur_depose, confotur_approuve]` == états `confotur_*` du workflow (ordre
|
||||
pipeline) · la prose README recoupe l'artefact/le workflow exactement
|
||||
(anti-invention #6, rien à réécrire). Le défaut est la **surface ungated**.
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Confotur champs
|
||||
dérivés » avant `sys.exit`) : (0) **traçabilité** — MANIFEST `workflow_source` cite
|
||||
bien `crm/workflow_vente/workflow_vente_spec.json` ; (a) **cross-artefact** —
|
||||
`dossier_vente.options` (Link) == workflow `document_type` ; (b) **prose** — la
|
||||
valeur README « (= `…`) » == workflow `document_type` ; (c) **cross-artefact** —
|
||||
`estado.options` == `update_value` des états `confotur_*` du workflow (ORDRE
|
||||
pipeline) ; (c′) toute option `estado` porte le préfixe `confotur` (le README
|
||||
l'affirme) ; (d) **prose** — le bullet `estado` DÉCLARE la dérivation (`confotur_*`
|
||||
+ workflow vente). Un claim absent échoue AUSSI (traçabilité #6). Direction
|
||||
README/artefact→workflow spec.
|
||||
|
||||
**6 morsures vérifiées** : README `dossier_vente` valeur `OTO Dossier Vente→OTO
|
||||
Dossier de Vente` (prose périmée, b) · README bullet `estado` supprimé (claim
|
||||
INTROUVABLE, d) · **artefact** `estado.options` +`brouillon` (options ≠ workflow, c
|
||||
ET hors-préfixe, c′) · **artefact** `dossier_vente.options→OTO Autre Doc` (Link ≠
|
||||
document_type, a) · **MANIFEST** `workflow_source` déréférencé (dérivation non
|
||||
déclarée, 0) · **spec workflow** `document_type→OTO Dossier de Vente` (mord
|
||||
SIMULTANÉMENT l'artefact a ET la prose b — l'ancre est vive) ; restauré = green :
|
||||
6 checks verts · exit 0. Working tree byte-restauré (`git checkout --`, **JAMAIS**
|
||||
`git clean`, interdit absolu) · **7 gates re-verts**
|
||||
(`check_readme_claims`/`check_ci_integrity`/`check_docs`/`guard_constraints`/
|
||||
`check_artifacts`/`check_regression`/`validate_json`).
|
||||
|
||||
- `ci/README.md` (clause de la table récap du pipeline + paragraphe détaillé
|
||||
« Champs `dossier_vente`/`estado` du DocType CONFOTUR dérivés du workflow vente »)
|
||||
mis à jour.
|
||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; l'import réel
|
||||
du DocType `bench import-fixtures` reste côté VPS).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
## Session `20260801_173409` · Buffer S8 · Fiches agents/pied de page voix OTOIA : le **PIED DE PAGE CANONIQUE** « - Voix **Amélie QC** (**multilingual_v2**) pour toute interaction OTOIA » — répété à l'identique dans **11 des 13 fiches** `03_agents/*/AGENT.md` (toutes sauf `faisabilite`/`publiciste`, qui n'orchestrent pas OTOIA) — RECOPIE À LA MAIN les **trois** tokens de la contrainte **CLAUDE.md §Architecture cible** « Voix Amélie QC (multilingual_v2) » : prénom persona (`Amélie`), qualificatif de marque (`QC`), modèle de voix ElevenLabs (`multilingual_v2`). Cette surface était **HORS de tout gate**.
|
||||
|
||||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||||
@@ -2011,3 +2192,422 @@ spec == rapport · exit 0. Working tree byte-restauré (`git checkout --`, **JAM
|
||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; la confirmation
|
||||
des 4 open items réglementaires reste côté métier/VPS).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
## Session `20260801_190412` · Buffer S8 · Domaine Fiches agents/RBAC : l'**appartenance à `roles_allowed` du chat OTOIA** — QUI peut **invoquer** l'assistant OTOIA embarqué dans un portail — asserée EN PROSE par 2 fiches (`03_agents/rendu/AGENT.md:36` positive · `03_agents/mobile/AGENT.md:41` négative) était **HORS de tout gate d'appartenance**. C'est une **3e surface d'appartenance** DISTINCTE des deux déjà gatées : le **contrat** `rbac_50_roles.json` (attributs du rôle, blocs Fiches Faisabilité/Mobile) et le **`Has Role`** `workspace.json` (accès console, bloc Fiches Workspace). Le contrôle d'invocation du chat vit dans un 3e artefact — `frontend/chat_otoia/out/chat_mount.json` (`roles_allowed` par portail) — que le bloc Chat OTOIA amont ne gate que sur l'IDENTITÉ persona/capabilities + la COMPOSITION (5 mounts ⇔ 5 portails), AVEUGLE à QUEL rôle figure dans quelle `roles_allowed`.
|
||||
|
||||
**Tâche** : **Sprint 8 · buffer** (QA/DevOps — série anti-dérive CLAUDE.md #6, roadmap fonctionnellement close). **Même patron EXACT** que le bloc de membership `Has Role` (juste au-dessus dans `check_readme_claims.sh`) — appliqué à un **artefact + une sémantique DIFFÉRENTS** : accès console (`Has Role`) ≠ droit d'invocation du chat (`roles_allowed`).
|
||||
|
||||
**Dérive silencieuse fermée** :
|
||||
- `03_agents/rendu/AGENT.md:36` — POSITIVE : rôle « OTO Faisabilité Rendu 3D » ∈ `roles_allowed` du portail NOMMÉ `construction` (déclenchement des rendus assistés).
|
||||
- `03_agents/mobile/AGENT.md:41` — NÉGATIVE d'honnêteté (#6) : rôle « OTO Plateforme Mobile » (famille `plateforme`) dans AUCUNE `roles_allowed` (le chat ne couvre que les portails métier).
|
||||
- Source faisant autorité : `frontend/chat_otoia/out/chat_mount.json[].roles_allowed` (byte-gaté par `check_artifacts`), `erpnext_role_name` résolu du contrat par `id` (zéro duplication).
|
||||
- Piège : ajouter le rôle mobile à une `roles_allowed` = **SUR-EXPOSITION** (le dev mobile gagnerait le droit de piloter l'IA d'un portail métier — l'escalade même que #6 refuse) ; retirer le rôle rendu de la `roles_allowed` construction = perte du déclenchement assisté ; DÉPLACER le rôle vers un autre portail — laisse la fiche périmée EN SILENCE pendant que l'artefact dit autre chose. Aucune suite `tests/` (qui teste des FONCTIONS de montage, pas la prose d'une fiche) n'attrape ce « vert trompeur ».
|
||||
- **État courant** : aucune valeur périmée — rendu ∈ construction (et lui seul), mobile ∉ tout (anti-invention #6, rien à réécrire). Le défaut est la **surface ungated**.
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Fiches agents · appartenance à `roles_allowed` du chat OTOIA » après le bloc Fiches Workspace) : index recomputé `erpnext_role_name → {portails autorisant}`, puis (a) **in_named_portail** (rendu) — le portail nommé est data-derived (== `portail` du rôle au contrat, **triple ancrage** : nommé == contrat == unique portail autorisant), membership == {ce portail}, prose citant « invoquer le chat OTOIA » ; (b) **not_in_any** (mobile) — rôle ABSENT de TOUTE `roles_allowed`. Portail nommé fantôme (absent des mounts) = échec (anti-typo). Claim absent = échec (traçabilité #6). Invariant vérifié en amont : chaque rôle ∈ ≤1 `roles_allowed`, == son `portail` contrat.
|
||||
|
||||
**6 morsures vérifiées** (3 côté artefact · 3 côté fiche/bord) : artefact retire rendu de `construction` (∉ aucun portail) · artefact ajoute mobile à `ventes` (SUR-EXPOSITION #6 VIOLÉE) · artefact ajoute AUSSI rendu à `compta` (droit élargi, fiche nomme 1 seul) · fiche rendu nomme le mauvais portail (`construction→compta`, INTROUVABLE) · fiche mobile retire le token `roles_allowed` (INTROUVABLE) ; restauré = green : rendu ∈ `{construction}` · mobile ∉ tout · exit 0. Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit absolu) · **7 gates re-verts** (`validate_json`/`check_docs`/`guard_constraints`/`check_artifacts`/`check_ci_integrity`/`check_readme_claims`/`check_regression`).
|
||||
|
||||
- `ci/README.md` (recap `check-readme-claims` + paragraphe détaillé « 3e surface d'appartenance · `roles_allowed` du chat OTOIA ») mis à jour.
|
||||
- **Note memory** : la classe « agent-fiche-role-attrs-ungated » est désormais CLOSE (attributs contrat = Fiches Faisabilité/Mobile ; `Has Role` = Fiches Workspace ; `roles_allowed` chat = ce bloc). Candidat propre restant : la fiche `ifc_speckle:34` (attributs contrat déjà gatés) + la row acceptance S3 « viewer 3D » (déjà gatée QA).
|
||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ; édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; le montage réel du chat reste côté runner/VPS).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
---
|
||||
|
||||
## Session 20260801_193414 · Sprint 8 · buffer · Gate d'IDENTITÉ des comptes de tests self-reportés par les README de MODULE (#6)
|
||||
|
||||
**Contexte** : la série anti-dérive Sprint-8 gate chaque surface data-derived contre sa source de vérité. Tous les blocs de **comptes de tests** existants (`ci/check_readme_claims.sh`) visent `03_agents/*/AGENT.md` : la cellule « Tests » des tables via `row_re`, les agrégats prose de `crm`/`erpnext_backend`, et les cinq claims per-suite « hors table » (seo/portails/chat_otoia/confotur/deploy_runbook). AUCUN ne touche le README du **MODULE** lui-même — pourtant `05_deliverables_mvp/<suite>/README.md` se re-déclare, en propre, le compte de SA suite à plusieurs endroits.
|
||||
|
||||
**Surface trouvée (ungated)** : **27 claims sur 16 READMEs de module**, sous trois formulations récurrentes :
|
||||
- commentaire de la commande unittest : `discover -s tests -v # N tests (…)` ;
|
||||
- bullet « Vérification en-repo » : `→ **N/N verts**` (six modules RBAC/faisabilité/CRM) ;
|
||||
- justification d'auto-score 4Big : `Validé statiquement en-repo (N tests verts + …)`.
|
||||
Ces nombres sont SAISIS À LA MAIN dans le doc d'entrée de chaque module et se périment dès qu'un `def test_` est ajouté/retiré : la source faisant autorité (`qa/regression/out/regression_plan.json` → `auth = plan.suites[path].test_methods`, recomptée à chaque build par découverte réelle, byte-gatée par `check_artifacts` + fraîcheur du run par `check_regression`) se met à jour tandis que la prose du README rote EN SILENCE — « vert trompeur » de la MÊME classe que la cellule « Tests » des fiches, mais sur la surface que `row_re` n'atteint pas (il ne lit le README de module QUE comme *cible de lien*). Aucune suite `tests/` (qui teste des FONCTIONS de génération, jamais la prose du README) n'attrape ce périmé.
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « READMEs de MODULE · comptes de tests self-reportés » juste après le bloc per-suite « hors table », d'où `auth` est déjà en portée · zéro rechargement · #6) : table de config `MODULE_README_TESTS` = liste `(suite_path, [motifs ancrés])`. Pour chaque module : `auth[suite_path]` recomputé, chaque motif DOIT matcher (claim absent = régression #6) ET tous ses groupes capturés == `auth`. Le motif `**N/N verts**` capture DEUX groupes → les deux doivent valoir `auth` : un `25/24 verts` internement incohérent mord aussi. Chaque motif est ancré sur un contexte distinctif (`discover -s tests…# N tests`, `**N/N verts**`, `en-repo (N tests verts`, `test_confotur.py # N tests`…) pour viser LE compte de CETTE suite sans capter un autre nombre.
|
||||
- **Cinq modules volontairement HORS table** (`frontend/chat_otoia`, `mobile/app_config`, `publiciste`, `qa/acceptance`, `qa/audit_4big`) : leur README ne self-reporte AUCUN compte de tests (vérifié) — rien à ancrer ; un futur claim = l'ajouter à la table. Noté dans le commentaire du bloc.
|
||||
|
||||
**4 morsures vérifiées** (chaque README restauré depuis backup — **JAMAIS** `git checkout .`/`git clean`, interdits absolus) :
|
||||
1. drift commentaire (`faisabilite/generator` 16→17 tests) → ✗ « dit 17 MAIS source dit 16 » ;
|
||||
2. incohérence interne `N/N` (`rbac/apply_plan` `16/16`→`16/17 verts`) → ✗ « dit 16/17 MAIS source dit 16 » ;
|
||||
3. disparition de claim (`legal/confotur` prose auto-score « diffable, 44 tests (dont… » retirée) → ✗ « claim INTROUVABLE (attendu 44) » ;
|
||||
4. drift auto-score prose (`rbac/fixtures_gen` `(11 tests verts`→`(12 tests verts`) → ✗ « dit 12 MAIS source dit 11 ».
|
||||
Restauré = green : `rc=0`, **440 checks de base intacts (diff vide) + 27 nouveaux**. Gates sœurs re-verts : `check_ci_integrity` rc=0 · `check_docs` rc=0.
|
||||
|
||||
- En-tête du gate mis à jour (inventaire des surfaces couvertes : nouvelle entrée « comptes de tests self-reportés par MODULE »).
|
||||
- **Note memory** : classe « comptes de tests » — désormais couverte sur TROIS surfaces (cellule « Tests » des fiches via `row_re` · agrégats prose fiches · **README de module**, ce bloc) + les cinq claims per-suite hors table. Source unique = `auth` (plan.suites[].test_methods).
|
||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ; édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
## Session `20260801_200419` · Buffer S8 · Fiche DevOps : gate du **COMPTE de suites gated** (« 22 suites gated ») — sémantique DISTINCTE des comptes de tests par suite
|
||||
|
||||
**Contexte** : la série anti-dérive Sprint-8 gate chaque surface data-derived contre
|
||||
sa source de vérité (CLAUDE.md #6, roadmap fonctionnellement close). Tous les blocs de
|
||||
comptes de tests de `ci/check_readme_claims.sh` recomputent un compte de **méthodes**
|
||||
`def test_` (`auth[path]` = `plan.suites[path].test_methods`) : la cellule « Tests »
|
||||
des tables via `row_re`, les agrégats prose crm/erpnext_backend, les 5 claims per-suite
|
||||
« hors table », et les READMEs de module. Une surface d'une **classe voisine mais
|
||||
distincte** restait ungated.
|
||||
|
||||
**Surface trouvée (ungated)** : `03_agents/devops/AGENT.md:24` — dans la table des
|
||||
livrables DevOps, la cellule « Tests » de la row du **pipeline CI**
|
||||
(`.gitea/workflows/ci.yml` + `ci/`) affiche « **22 suites gated** » : non pas un compte
|
||||
de tests, mais le **nombre de SUITES** que la CI passe au crible, soit
|
||||
`regression_plan.totals.suites`. Ce nombre est saisi À LA MAIN et **aucun** gate ne
|
||||
l'atteignait :
|
||||
- `row_re` échoue DEUX fois : l'ancre de lien est `ci.yml`/`ci/` (pas un module de
|
||||
`auth`) ET la cellule porte le suffixe « suites gated » (pas un entier nu) ;
|
||||
- l'agrégat de la fiche QA (`03_agents/qa/AGENT.md:35` « **22 suites gated · 564
|
||||
tests…** », gaté sur `regression_run`) est une **surface distincte** (autre fichier,
|
||||
autre motif). La MÊME valeur 22 vit donc à DEUX endroits — **un seul** était gaté.
|
||||
|
||||
**Dérive silencieuse fermée** : ajouter/retirer un module gated fait bouger
|
||||
`reg["suites"]` (recompté à chaque build par découverte réelle des suites, byte-gaté par
|
||||
`check_artifacts`) tandis que cette cellule DevOps rote EN SILENCE ⇒ la doc d'identité de
|
||||
l'agent DevOps affirmerait un **périmètre de couverture CI faux** — le « vert trompeur »
|
||||
que #6 interdit. Aucune suite `tests/` (FONCTIONS, pas la prose de fiche) ne l'attrape.
|
||||
**État courant** : valeur exacte (22 == 22), le défaut est la **surface ungated** (rien
|
||||
à réécrire · anti-invention #6).
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Fiche DevOps · COMPTE de
|
||||
suites gated » juste après le bloc per-suite « hors table », d'où `reg` est déjà en
|
||||
portée · zéro rechargement) : on RECOMPUTE depuis `reg["suites"]`
|
||||
(`regression_plan.totals.suites`, source unique) et on exige que la cellule l'écrive
|
||||
EXACTEMENT. Motif ANCRÉ sur le label de rôle « CI/CD Gitea Actions » de CETTE row →
|
||||
vise la bonne cellule. Claim absent = échec (traçabilité #6). **Cohérence croisée** :
|
||||
`reg["suites"]` == `regression_run` `len(suites)` (la source du compte de la fiche QA)
|
||||
⇒ une divergence plan↔run mord ici aussi.
|
||||
|
||||
**5 morsures vérifiées** (2 côté fiche · 2 côté artefact · 1 cross-cohérence) :
|
||||
1. cellule 22→23 → ✗ « dit 23 MAIS source dit 22 » ;
|
||||
2. claim retiré (`| gated |`) → ✗ « cellule « N suites gated » INTROUVABLE » ;
|
||||
3. `plan.totals.suites` 22→21 (fiche périmée) → ✗ divergence SOURCE + ✗ « dit 22 MAIS
|
||||
source dit 21 » ;
|
||||
4. `regression_run` privé d'une suite (plan↔run divergent) → ✗ « incohérence SOURCE :
|
||||
plan.suites=22 ≠ run len=21 » ;
|
||||
5. restauré = green (rc=0).
|
||||
Working tree byte-restauré via `git checkout -- <fichier précis>` (**JAMAIS**
|
||||
`git checkout .` / `git clean`, interdits absolus). **7 gates re-verts** :
|
||||
`validate_json` / `check_docs` / `guard_constraints` / `check_artifacts` /
|
||||
`check_ci_integrity` / `check_readme_claims` / `check_regression` (tous rc=0).
|
||||
|
||||
- En-tête du gate mis à jour (inventaire des surfaces couvertes : nouvelle entrée
|
||||
« COMPTE de suites gated de la fiche devops ») + `ci/README.md` (recap
|
||||
`check-readme-claims` : nouvelle clause du compte de suites gated).
|
||||
- **Note memory** : la classe « comptes de tests » (méthodes `def test_`) est couverte
|
||||
sur 4 surfaces + les 5 per-suite ; le COMPTE de **suites** (`plan.totals.suites`) est
|
||||
une classe voisine — désormais gaté sur ses DEUX surfaces (fiche QA agrégat déjà gaté ·
|
||||
fiche DevOps cellule, ce bloc).
|
||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
## Session `20260801_203424` · Buffer S8 · Audit 5D (4e surface du même README) : gate de l'IDENTITÉ des **LIVRABLES AUDITÉS** — la liste des hand-off `out/*.json` que l'audit de second niveau LIT comme matière première
|
||||
|
||||
**Contexte** : la série anti-dérive Sprint-8 gate chaque surface data-derived contre
|
||||
sa source de vérité (CLAUDE.md #6, roadmap fonctionnellement close). Trois blocs
|
||||
`audit_5d` de `ci/check_readme_claims.sh` couvrent déjà le MÊME README : la **synthèse**
|
||||
(17 contrôles / 5 dimensions + ventilation verdict), l'**énumération des open items**
|
||||
(`control→dimension→propriétaire`) et l'**IDENTITÉ des 5 dimensions** (`id→titre→
|
||||
reference`). Une **4e surface** du même README restait ungated.
|
||||
|
||||
**Surface trouvée (ungated)** : `05_deliverables_mvp/qa/audit_5d/README.md:21-27` —
|
||||
section « ## Livrables audités (source = leur `out/`) » : une **liste de 5 puces** qui
|
||||
énumère À LA MAIN les hand-off `out/*.json` que l'auditeur charge réellement
|
||||
(`crm/workflow_vente/out/workflow.json` · `crm/dossier_vente/out/doctype_oto_dossier_
|
||||
vente.json` · `crm/commissions/out/commission_plan.json` · `fiscal/ecf_dgii/out/
|
||||
ecf_plan.json` · `legal/confotur/out/doctype_confotur_application.json`). Aucun bloc ne
|
||||
la touchait — vérifié : le seul `audited_artifacts` de tout le gate était dans un
|
||||
**commentaire** ; les 3 blocs audit_5d ne `load()` que `controls_total`/`totals`/
|
||||
`open_items`/`dimensions[]`.
|
||||
|
||||
**Source faisant autorité** : `qa/audit_5d/out/MANIFEST.json` clé `audited_artifacts`
|
||||
(byte-gaté par `check_artifacts` ⇒ reproduit à chaque build via
|
||||
`sorted(ARTIFACT_PATHS.values())` dans `audit_5d_gen.py:61` — le registre des hand-off
|
||||
que `qalib/artifacts.py::load_artifacts()` charge). Le README énumère les 5 chemins
|
||||
dans un **ORDRE DIFFÉRENT** du MANIFEST (workflow 2e ici, 3e au MANIFEST trié) ⇒
|
||||
comparaison par **ENSEMBLE**.
|
||||
|
||||
**Dérive silencieuse fermée** : brancher un nouveau livrable amont sur l'audit
|
||||
(nouvelle entrée `ARTIFACT_PATHS` → nouveau chemin dans `audited_artifacts`) ou en
|
||||
retirer un laisse la section README **périmée en silence** pendant que l'audit lit un
|
||||
autre jeu de fichiers ⇒ le lecteur/banquier croirait l'audit couvrir un **périmètre
|
||||
qu'il ne couvre plus** (l'invention #6 interdit), qu'aucune suite `tests/` (FONCTIONS
|
||||
de contrôle, pas la prose) n'attrape. **État courant** : les 5 puces == registre
|
||||
exactement (rien à réécrire · anti-invention #6), le défaut est la **surface ungated**.
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Audit 5D (4e surface) ·
|
||||
IDENTITÉ des LIVRABLES AUDITÉS » entre le bloc des 5 dimensions et le bloc DevOps
|
||||
run-book) : on RECOMPUTE l'ensemble depuis `MANIFEST.audited_artifacts` (zéro
|
||||
duplication du registre) et on parse les puces `` - `<chemin>` `` de la section
|
||||
« ## Livrables audités » → égalité par ENSEMBLE exigée (absent ET fantôme mordus, via
|
||||
set-diff `absents`/`en trop`). **Cohérences croisées bonus** : **(a)** chaque chemin
|
||||
audité RÉSOUT un fichier commité sur disque (`os.path.exists` — le `_load` de l'auditeur
|
||||
lève `FileNotFoundError` sinon, audit à vide impossible) ; **(b)** |livrables audités|
|
||||
== |alias distincts d'artefacts référencés par les `controls[].artifacts` de
|
||||
`audit_spec.json`| (un artefact chargé mais jamais contrôlé, ou un alias contrôlé sans
|
||||
chemin de chargement → `KeyError` runtime, désynchronise). Section absente = échec
|
||||
(traçabilité #6). `import os` ajouté au bloc (non importé globalement).
|
||||
|
||||
**6 morsures vérifiées** (4 côté README · 2 côté source) :
|
||||
1. README puce `workflow.json` retirée → ✗ « absents=[…workflow.json] » ;
|
||||
2. README puce FANTÔME `demo/scenarios/out/run_sheet.json` ajoutée → ✗ « en trop
|
||||
(fantôme)=[…run_sheet.json] » ;
|
||||
3. README typo `commission_plan.json`→`commissions_plan.json` → ✗ absents ET fantôme ;
|
||||
4. README header de section renommé → ✗ « section « ## Livrables audités »
|
||||
INTROUVABLE/vide » ;
|
||||
5. `audit_spec.json` : alias `phantom_alias` ajouté à un contrôle → ✗ « désynchro
|
||||
registre/spec : 5 livrables MAIS 6 alias distincts contrôlés » (cross-anchor b) ;
|
||||
6. `MANIFEST.audited_artifacts` : un chemin pointé vers un fichier inexistant → ✗
|
||||
« INTROUVABLES sur disque » (cross-anchor a) + ✗ README périmé.
|
||||
Restauré = green : 5 puces == registre · 5 == 5 alias · 5 fichiers résolus · exit 0.
|
||||
Working tree byte-restauré via `git checkout -- <fichier précis>` (**JAMAIS**
|
||||
`git checkout .` / `git clean`, interdits absolus). **7 gates re-verts** :
|
||||
`validate_json` / `guard_constraints` / `check_docs` / `check_artifacts` /
|
||||
`check_regression` / `check_ci_integrity` / `check_readme_claims` (tous rc=0).
|
||||
|
||||
- `ci/README.md` mis à jour : clause de la row récap `check-readme-claims` (surface
|
||||
audit 5D étendue) + paragraphe détaillé « 4ᵉ surface du même README de l'audit 5D ».
|
||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; l'exécution
|
||||
réelle de l'audit `bench` reste côté VPS).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
## Session `20260801_213444` · Buffer S8 · Fiche ONAPI/Legal : 2ᵉ SURFACE PROSE des ENTITÉS PORTEUSES
|
||||
|
||||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA — anti-dérive doc). Roadmap
|
||||
plancher atteinte ; on continue de fermer les surfaces prose data-derived encore
|
||||
ungatées. Cible de cette session : `03_agents/onapi_legal/AGENT.md:54`.
|
||||
|
||||
**Surface trouvée (ungatée)** : la fiche ONAPI/Legal décrit le champ Select
|
||||
`entite_porteuse` du DocType CONFOTUR par « **les 7 entités de CLAUDE.md #Entités
|
||||
(WAF · WA SRL · AC Arias Cuevas · Consortium ECR DR · Helios RD · Ploutos · 9060
|
||||
QC)** ». C'est un **COMPTE littéral** (« 7 ») **+** l'**énumération complète** — une
|
||||
**SECONDE surface prose** du même menu que le champ `entite_porteuse` offrira.
|
||||
|
||||
Le bloc « Confotur entités » déjà en place ancre le champ à CLAUDE.md §Entités et
|
||||
gate la ligne du README `legal/confotur` (surface **(e)**), mais ce motif est ancré
|
||||
sur `05_deliverables_mvp/legal/confotur/README.md` — **il ne vise pas `03_agents/`**.
|
||||
La fiche restait donc **hors de tout gate** : recompter la §Entités (aujourd'hui 7)
|
||||
n'atteignait jamais cette phrase.
|
||||
|
||||
**Dérive silencieuse fermée** : AJOUTER / RETIRER / RENOMMER une entité dans
|
||||
CLAUDE.md §Entités (source ancre) → régénérer propage le menu de l'artefact **et** la
|
||||
ligne du README confotur, MAIS la fiche onapi_legal se **périme en silence** — elle
|
||||
annoncerait « 7 entités » quand il y en a 8, ou nommerait `Ploutos` là où le menu ne
|
||||
l'offre plus. L'agent ERPNext Backend qui seede le DocType croirait le déroulant
|
||||
couvrir un périmètre d'entités qu'il ne couvre plus (l'**invention #6** interdit).
|
||||
Aucune suite `tests/` (FONCTIONS de build du DocType, pas la prose d'une fiche) ne
|
||||
l'attrape. **État courant** : la fiche == §Entités == menu artefact exactement
|
||||
(rien à réécrire · #6) ; le défaut était la surface **ungatée**.
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Fiche ONAPI/Legal ·
|
||||
2ᵉ SURFACE PROSE des ENTITÉS PORTEUSES », inséré juste après le bloc « Confotur
|
||||
entités » et avant le bloc Chat OTOIA) : on **re-dérive** la liste depuis les tokens
|
||||
en gras de la section « ## Entités » de CLAUDE.md (source ancre · zéro duplication)
|
||||
et on exige de la fiche — **(a)** le COMPTE littéral (« les N entités ») ==
|
||||
|§Entités| ; **(b)** l'énumération == §Entités **ORDRE EXACT** (absent ET fantôme
|
||||
mordus par set-diff + comparaison ordonnée) ; **(c)** l'ancre « CLAUDE.md #Entités »
|
||||
citée sur la ligne ; **(d)** cross-check bonus — l'énumération == options
|
||||
`entite_porteuse` de l'artefact CONFOTUR byte-gaté (la fiche décrit **exactement** le
|
||||
menu que le DocType offrira). Ligne absente = échec (traçabilité #6).
|
||||
|
||||
**6 morsures vérifiées** (5 côté fiche · 1 côté artefact) :
|
||||
1. compte `7`→`8` → ✗ (a) « fiche dit 8 entités MAIS §Entités en porte 7 » ;
|
||||
2. `Ploutos` retiré de l'énumération → ✗ (b) « absent(s)=['Ploutos'] » ;
|
||||
3. entité FANTÔME `Fantom SA` ajoutée → ✗ (b) « fantôme(s)=['Fantom SA'] » ;
|
||||
4. réordre `WAF`↔`WA SRL` → ✗ (b) « ordre : fiche […] ≠ §Entités […] » ;
|
||||
5. ancre `#Entités` retirée de la ligne → ✗ (c) « ne cite pas CLAUDE.md #Entités » ;
|
||||
6. option `Ploutos`→`Ploutos SRL` dans l'artefact CONFOTUR → ✗ (d) « fiche […] ≠
|
||||
menu artefact […] → la fiche décrit un menu que le DocType n'offre pas ».
|
||||
Restauré = green : (a)(b)(c)(d) tous ✓ · exit 0. Working tree byte-restauré via
|
||||
`git checkout -- <fichier précis>` (**JAMAIS** `git checkout .` / `git clean`,
|
||||
interdits absolus). **7 gates re-verts** : `validate_json` / `guard_constraints` /
|
||||
`check_docs` / `check_artifacts` / `check_regression` / `check_ci_integrity` /
|
||||
`check_readme_claims` (tous rc=0).
|
||||
|
||||
- `ci/README.md` mis à jour : paragraphe « Entités porteuses du DocType CONFOTUR »
|
||||
étendu d'une clause « **2ᵉ surface prose (fiche ONAPI/Legal)** » (compte + liste +
|
||||
cross-check menu artefact).
|
||||
- **Note anti-stale** : la mémoire `agent-fiche-role-attrs-ungated` est désormais
|
||||
**périmée** — les attributs des fiches mobile / rendu / ifc_speckle (niveau, scope,
|
||||
modules, permissions, entité) SONT déjà gatés (blocs « Fiche Mobile » et « Fiches
|
||||
Faisabilité »). La classe résiduelle réelle est celle des LISTES data-derived
|
||||
transcrites en prose de fiche, dont cette session ferme l'occurrence entités.
|
||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; l'application
|
||||
réelle du DocType par `bench` reste côté agent ERPNext Backend).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
---
|
||||
|
||||
## Sprint 8 · buffer · Chat OTOIA : gate d'IDENTITÉ de la LISTE D'INVARIANTS CI
|
||||
|
||||
**Contexte** : campagne anti-dérive documentaire (Sprint 8 · QA « regression
|
||||
tests exhaustifs »). Baseline des 7 gates vert avant intervention. Recherche
|
||||
(sous-agent Explore) de la prochaine classe de surface data-derived transcrite
|
||||
en prose mais NON gatée → candidat retenu : la section « ## Invariants (14) —
|
||||
garantis en CI » du README `frontend/chat_otoia` (README:53-60).
|
||||
|
||||
**Défaut** : cette section (a) ANNONCE un compte `(14)` puis (b) ÉNUMÈRE chaque
|
||||
invariant par son numéro entre parenthèses ((1)·(2)·…·(11, 13)·(12)·(14)). C'est
|
||||
la transcription À LA MAIN du REGISTRE réel des invariants du générateur — les
|
||||
marqueurs `# Invariant N ·` de `chat_otoia_gen.py` (source d'autorité : chaque
|
||||
marqueur = un contrôle appliqué par `validate()`). Le générateur se self-reporte
|
||||
en plus dans son message CLI (« schéma + 14 invariants verts. »), 3ᵉ transcription
|
||||
du même compte. Les blocs Chat OTOIA préexistants du gate couvrent des COMPTES
|
||||
d'artefact (blocks/mounts/portails) + l'IDENTITÉ persona/langues/endpoint —
|
||||
AUCUN ne touche la liste d'invariants : surface aveugle. Aucune suite `tests/` ne
|
||||
teste la PROSE ; le byte-gate d'artefact ignore le `.py` source ⇒ dérive
|
||||
silencieuse (ajouter `# Invariant 15` ⇒ README périmé sans échec).
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Chat OTOIA · IDENTITÉ
|
||||
de la LISTE D'INVARIANTS CI », inséré juste après le bloc « Chat OTOIA identité »
|
||||
et avant le bloc « Recette ») : on RECOMPUTE le registre depuis le SEUL
|
||||
registre-source (`re.findall(r"#\s*Invariant\s+(\d+)", chat_otoia_gen.py)`) et on
|
||||
exige — **(a)** le registre code est un ensemble CONTIGU `1..max` (lacune/doublon
|
||||
dans le ledger = défaut réel) ; **(b)** le message CLI « N invariants verts »
|
||||
== |registre| (self-report du `.py` cohérent avec son propre ledger) ; **(c)** le
|
||||
compte annoncé « ## Invariants (N) » du README == |registre| ; **(d)**
|
||||
l'ÉNUMÉRATION en prose (ints extraits des groupes `(...)` de la section, borne =
|
||||
prochain `## `) == registre EXACT — absent ET fantôme mordus par set-diff. Section
|
||||
ou compte absent = échec (disparition d'un chiffre = régression de traçabilité #6).
|
||||
|
||||
**5 morsures vérifiées** (working tree byte-restauré après chacune via
|
||||
`git checkout -- <fichier précis>`, JAMAIS `git checkout .` / `git clean`) :
|
||||
1. compte annoncé `14`→`15` → ✗ (c) « annonce (15) MAIS registre en compte 14 » ;
|
||||
2. numéro `(7)` retiré de la prose → ✗ (d) « absent(s)=[7] » ;
|
||||
3. numéro fantôme `20` ajouté à la prose → ✗ (d) « fantôme(s)=[20] » ;
|
||||
4. self-report CLI `14`→`13` → ✗ (b) « générateur dit 13 MAIS registre 14 » ;
|
||||
5. ledger code `# Invariant 7`→`77` → ✗ (a) « registre NON contigu […77] » +
|
||||
✗ (d) « absent(s)=[77] · fantôme(s)=[7] » (double morsure : ledger + prose).
|
||||
Restauré = green : (a)(b)(c)(d) tous ✓ (registre contigu 1..14 · 14 marqueurs).
|
||||
|
||||
- `ci/README.md` : la clause « montage Chat OTOIA » de la row `check-readme-claims`
|
||||
étendue de l'IDENTITÉ de la liste d'invariants (compte + énumération + self-report
|
||||
CLI recomputés du registre `# Invariant N`, set-diff + contiguïté).
|
||||
- **7 gates re-verts** : `validate_json` / `guard_constraints` / `check_docs` /
|
||||
`check_artifacts` / `check_regression` / `check_ci_integrity` /
|
||||
`check_readme_claims` (tous rc=0).
|
||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
---
|
||||
|
||||
## Sprint 8 · buffer · SEO : gate d'IDENTITÉ du COMPTE d'INVARIANTS CI
|
||||
|
||||
**Contexte** : campagne anti-dérive documentaire (Sprint 8 · QA « regression
|
||||
tests exhaustifs »). Baseline des 7 gates vert avant intervention. Recherche
|
||||
(sous-agent Explore) de la prochaine surface data-derived transcrite en prose
|
||||
mais NON gatée. L'agent a proposé 5 candidates « N invariants » ; chat_otoia
|
||||
étant déjà fermée au commit précédent, candidat retenu = le générateur SEO
|
||||
(`05_deliverables_mvp/seo/seo_gen.py` + `seo/README.md`).
|
||||
|
||||
**Défaut** : la source d'autorité du COMPTE D'INVARIANTS de validation SEO n'est
|
||||
PAS un artefact JSON (invisible à `check_artifacts` qui byte-gate les `out/*.json`)
|
||||
mais le LEDGER NUMÉROTÉ de la fonction `_validate` — les marqueurs `# N ·`
|
||||
(`# 1 ·` … `# 15 ·`) qui ouvrent chaque contrôle appliqué, analogue du registre
|
||||
`# Invariant N` de Chat OTOIA. Ce compte est transcrit À LA MAIN à SEPT endroits
|
||||
qu'AUCUN gate ne couvrait : le titre `## Garanties (N invariants)` du README + son
|
||||
bloc de commande (« schéma de sortie + N invariants »), plus CINQ chaînes du `.py`
|
||||
lui-même (docstring module L19, docstring `_validate` L57, aide `build` L24, message
|
||||
de succès CLI « N invariants verts. » L285, aide du sous-parseur `validate` L298).
|
||||
Le bloc SEO préexistant du gate ne couvre que des COMPTES d'ARTEFACT (mots-clés
|
||||
total + par langue, recomputés de MANIFEST.counts) — classe distincte, surface
|
||||
aveugle. Ajouter un contrôle `# 16 ·` à `_validate` ⇒ README + self-reports du `.py`
|
||||
mentent en silence pendant que la CI applique 16 contrôles (« vert trompeur » #6)
|
||||
— ni les suites `tests/` (FONCTIONS, jamais la prose) ni le byte-gate d'artefact
|
||||
(aveugle au `.py` source) ne l'attrapent.
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « SEO · IDENTITÉ du
|
||||
COMPTE d'INVARIANTS CI », inséré juste après le bloc SEO mots-clés et avant le bloc
|
||||
CRM pipeline vente) : on RECOMPUTE le ledger depuis le SEUL registre-source (les
|
||||
`# N ·` de `_validate`, extraits du corps de la fonction borné au prochain `def `)
|
||||
et on exige — **(a)** le ledger est CONTIGU 1..N (comparaison de la LISTE triée à
|
||||
`range(1,N+1)`, ⇒ mord lacune ET doublon) ; **(b)** TOUTE mention « N invariants »
|
||||
du `.py` == |ledger| (set des self-reports == {N}) ; **(c)** le compte annoncé
|
||||
« ## Garanties (N invariants) » du README == |ledger| ; **(d)** TOUTE mention
|
||||
« N invariants » du README == |ledger|. La prose du README RÉSUME les contrôles
|
||||
(11 puces `·`-séparées ≠ énumération numérotée 1:1) ⇒ on gate le COMPTE partout où
|
||||
il apparaît, PAS un set-diff de la liste. Section/compte absent = échec (#6).
|
||||
|
||||
**5 morsures vérifiées** (working tree byte-restauré après chacune via
|
||||
`git checkout -- <fichier précis>`, JAMAIS `git checkout .` / `git clean`) :
|
||||
1. README titre `15`→`16` → ✗ (c) « annonce (16) MAIS ledger 15 » + ✗ (d) « [15, 16] » ;
|
||||
2. README commande `15`→`14` → ✗ (d) « mention(s) [14, 15] MAIS ledger 15 » ;
|
||||
3. `.py` succès CLI `15`→`13` → ✗ (b) « self-report(s) [13, 15] MAIS ledger 15 » ;
|
||||
4. ledger `# 7 ·`→`# 77 ·` (lacune) → ✗ (a) « NON contigu […6, 77, 8…] » ;
|
||||
5. ledger `# 8 ·`→`# 7 ·` (doublon) → ✗ (a) « NON contigu […7, 7, 9…] »
|
||||
(la comparaison sur LISTE — non set — attrape le doublon, angle que
|
||||
l'approche set de chat_otoia aurait raté).
|
||||
Restauré = green : (a)(b)(c)(d) tous ✓ (ledger contigu 1..15 · 15 marqueurs).
|
||||
|
||||
- `ci/README.md` : la clause SEO de la row `check-readme-claims` étendue du COMPTE
|
||||
d'INVARIANTS CI (annonce + toutes mentions README + 5 self-reports `.py`
|
||||
recomputés du ledger `# N ·` de `_validate`, contiguïté 1..N).
|
||||
- **7 gates re-verts** : `guard_constraints` / `validate_json` / `check_docs` /
|
||||
`check_artifacts` / `check_regression` / `check_ci_integrity` /
|
||||
`check_readme_claims` (tous rc=0).
|
||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
---
|
||||
|
||||
## Sprint 8 · buffer · RBAC SPEC §5 : gate de la LIGNE D'AUTO-CONTRÔLE du « résumé »
|
||||
|
||||
**Contexte** : suite de la campagne anti-dérive documentaire (Sprint 8 · QA
|
||||
« regression tests exhaustifs »). Baseline des 7 gates verte avant intervention.
|
||||
Recherche (sous-agent Explore) de la prochaine surface data-derived transcrite en
|
||||
prose mais NON gatée — la plupart des COMPTES d'artefact sont déjà fermés. Le
|
||||
candidat retenu est une surface interne de `rbac/RBAC_50_ROLES_SPEC.md` : le §5.
|
||||
|
||||
**Défaut** : la SPEC RBAC a DÉJÀ trois gates (§3 ventilation par portail · §4
|
||||
colonne Entité · §7 run-book), mais son §5 « Les N rôles (résumé) » restait
|
||||
AVEUGLE. Ce §5 restitue le total de rôles sur TROIS surfaces prose : (i) le
|
||||
compte-titre « ## 5. Les 50 rôles (résumé) », (ii) NEUF comptes parenthétiques de
|
||||
regroupement (`**Ventes (8)**` …) et (iii) une LIGNE d'auto-contrôle arithmétique
|
||||
`_(6+8+4+7+5+8+4+2+6 = 50.)_`. AJOUTER un rôle au contrat (|rôles| 50→51) laisse le
|
||||
titre, la somme et le « = 50 » PÉRIMÉS en silence ; ÉDITER `Ventes (8)→(7)` sans
|
||||
toucher la ligne casse la cohérence titre↔somme — aucune suite `tests/` (FONCTIONS
|
||||
RBAC, jamais la prose de la SPEC) ni le byte-gate d'artefact ne l'attrape.
|
||||
|
||||
**Subtilité (memory `rbac-spec-portail-count-gate` : « §5 by-family is
|
||||
editorial »)** : les 9 regroupements sont ÉDITORIAUX — « Direction / Gouvernance »
|
||||
agrège des rôles de familles direction+finance, ≠ la colonne `famille` du contrat.
|
||||
On NE mappe donc PAS groupe↔famille (ce serait une dérive fausse). On gate
|
||||
UNIQUEMENT ce qui est data-derived et vérifiable SANS ce mapping.
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « 1septies) §5 », inséré après
|
||||
le bloc §4 et avant le bloc apply_plan) : on RECOMPUTE N = |rôles| du contrat
|
||||
(`rbac_50_roles.json`, byte-gaté par check_artifacts) et on exige — **(a)** le
|
||||
compte-titre « ## 5. Les N rôles » == N ; **(b)** les 9 comptes de regroupement ==
|
||||
EXACTEMENT, dans l'ordre, les termes de la ligne arithmétique (cohérence interne
|
||||
prose↔somme, comparaison de LISTES ordonnées) ; **(c)** l'arithmétique est VRAIE
|
||||
(Σ termes == membre droit) ; **(d)** le membre droit == N. Section/titre/ligne/
|
||||
comptes absents = échec (#6).
|
||||
|
||||
**5 morsures vérifiées** (working tree byte-restauré après chacune via
|
||||
`git checkout -- <fichier précis>`, JAMAIS `git checkout .` / `git clean` ;
|
||||
gate rc=1 sous mutation, rc=0 restauré) :
|
||||
1. titre `50`→`51` → ✗ (a) « titre dit 51 rôles MAIS le contrat en compte 50 » ;
|
||||
2. regroupement `Ventes (8)`→`(9)` → ✗ (b) « [6, 9, 4…] ≠ termes [6, 8, 4…] » ;
|
||||
3. ligne `= 50.`→`= 49.` → ✗ (c) « écrit = 49 MAIS Σ = 50 » + ✗ (d) « totalise
|
||||
49 MAIS le contrat compte 50 » (double morsure) ;
|
||||
4. terme `6+8+…`→`7+8+…` → ✗ (b) « termes [7, 8…] ≠ [6, 8…] » + ✗ (c) « = 50
|
||||
MAIS Σ = 51 » (double morsure) ;
|
||||
5. suppression de la ligne d'auto-contrôle → ✗ « ligne … INTROUVABLE » (absence).
|
||||
Restauré = green : (a)(b)(c)(d) tous ✓ (titre 50 · 9 comptes == 6+8+4+7+5+8+4+2+6
|
||||
· Σ=50 · membre droit 50 == |rôles|).
|
||||
|
||||
- `ci/README.md` : la row `check-readme-claims` étendue de la clause §5 (compte-
|
||||
titre + 9 comptes de regroupement éditoriaux + ligne d'auto-contrôle, sans
|
||||
mapping groupe↔famille).
|
||||
- **7 gates re-verts** : `guard_constraints` / `validate_json` / `check_docs` /
|
||||
`check_artifacts` / `check_regression` / `check_ci_integrity` /
|
||||
`check_readme_claims` (tous rc=0).
|
||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,328 @@
|
||||
# Daily Report · 2026-08-02 · Claude Code DTP Worker
|
||||
|
||||
**Session** : `20260802_110539`
|
||||
**Phase roadmap** : Sprint 8 · *Launch + Buffer* — livrables « Regression tests
|
||||
exhaustifs » (QA) + « Corrections finales » (buffer).
|
||||
|
||||
## Tâche exécutée
|
||||
**Sprint 8 · QA — sweep de vérification launch-readiness sur arbre propre + reprise
|
||||
du canal `daily_reports/`.**
|
||||
|
||||
Ce rapport comble un **trou de reporting** : le canal canonique des rapports
|
||||
quotidiens ([`04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md`](../../04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md)
|
||||
§Escalations · référencé par les 13 fiches `03_agents/*/AGENT.md`) n'avait **plus
|
||||
d'instantané consolidé depuis `2026-07-30`**, alors que ~2 douzaines de sessions
|
||||
buffer ont continué. Leur trace fine existe (journal par session
|
||||
[`05_activity_log/`](../../05_activity_log/2026-08-02.md)) mais **aucun snapshot
|
||||
sourcé de l'état MVP** n'existait pour la phase Sprint 8. Ce rapport le produit,
|
||||
chaque chiffre **re-vérifié contre l'artefact commité** ci-dessous (anti-invention
|
||||
`CLAUDE.md` #6 · zéro donnée nouvelle).
|
||||
|
||||
## Contexte / analyse
|
||||
- Relu `CLAUDE.md`, la roadmap, `MEMORY.md`, le journal `05_activity_log/2026-08-02.md`,
|
||||
les fiches `crm` + `bim` (audit d'exactitude doc-vs-réalité).
|
||||
- **Tous les sprints 1→7 sont livrés côté repo** ; on est en **buffer Sprint 8**.
|
||||
La série récente a épuisé les surfaces driftables évidentes en **durcissant des
|
||||
gates existants** (dernier : blind-spot « comptes de tests par suite » sur la
|
||||
cellule `rbac` pointant une SPEC, commit `ca15e7e`).
|
||||
- **Décision** (workflow #5 · CLAUDE.md — ne pas empiler un gate redondant) : plutôt
|
||||
qu'un gate N+1, **auditer l'exactitude** des fiches agents + **produire l'instantané
|
||||
QA manquant**. La phase Sprint 8 attend précisément une **vérification de régression
|
||||
exhaustive**, pas de nouveau module (contrainte « pas d'invention de modules »).
|
||||
|
||||
## Réalisé
|
||||
- **Sweep des 7 gates CI** sur l'arbre propre — tous **verts (exit 0)** :
|
||||
`check_ci_integrity` · `check_artifacts` (reproductibilité byte-identique des
|
||||
`out/`) · `check_docs` · `check_readme_claims` · `check_regression` ·
|
||||
`guard_constraints` · `validate_json`. Détail : [`ci/README.md`](../../ci/README.md).
|
||||
- **Audit doc-vs-réalité de 2 fiches agents** (interdit CLAUDE.md « documenter du
|
||||
code sans vérifier son existence courante ») :
|
||||
- `03_agents/crm/AGENT.md` — table des livrables **exacte** : `commissions=25`,
|
||||
`dossier_vente=31`, `workflow_vente=25`, total **81 tests**, recomptés depuis
|
||||
`plan.suites[*].test_methods` de
|
||||
[`regression_plan.json`](../qa/regression/out/regression_plan.json). ✅
|
||||
- `03_agents/bim/AGENT.md` — son **seul point de contact commité** cité,
|
||||
`faisabilite/generator/genlib/renderer.py`, **existe** et rend bien le **Volet 4 ·
|
||||
Ingénierie** en placeholders `{{…}}` (`_v`/`_money`/`_num` · anti-invention #6).
|
||||
Aucune sur-promesse d'artefact BIM en-repo. ✅
|
||||
- **Reprise du canal `daily_reports/`** (ce fichier) : instantané MVP consolidé sourcé.
|
||||
|
||||
## État courant MVP · 100 % sourcé (aucun chiffre saisi à la main)
|
||||
| Dimension | Valeur | Verdict | Source commitée |
|
||||
|---|---|---|---|
|
||||
| Qualité 4Big | **22/22 modules à 100/100** (seuil 95 · #5) | `PASS` | [`qa/audit_4big/out/quality_report.json`](../qa/audit_4big/out/quality_report.json) |
|
||||
| Régression (plan) | **22 suites · 564 méthodes** · 0 sous le seuil (min 10) | `PASS` | [`qa/regression/out/regression_plan.json`](../qa/regression/out/regression_plan.json) |
|
||||
| Régression (run agrégé) | **22 suites · 564 tests · 564 passés · 0 échec · 0 erreur** | `PASS` | [`qa/regression/out/regression_run.json`](../qa/regression/out/regression_run.json) |
|
||||
| Recette roadmap | **15 promesses** (8 livrables sprint + 7 métriques MVP) · **15 `in_repo`** | `true` | [`qa/acceptance/out/acceptance_matrix.json`](../qa/acceptance/out/acceptance_matrix.json) |
|
||||
| Fiches agents | **13 agents** | — | `03_agents/*/AGENT.md` |
|
||||
| Gates CI | **7 gates statiques** verts + reproductibilité `out/` byte-identique | vert | [`ci/README.md`](../../ci/README.md) |
|
||||
|
||||
## Vérifications effectuées (en-repo, sans toucher au VPS)
|
||||
- 7 gates CI → **exit 0** sur l'arbre propre (dont `check_artifacts` : tout `out/`
|
||||
se régénère à l'identique depuis son générateur `build`).
|
||||
- Recalcul indépendant des agrégats (`python3` sur les artefacts) **concordant**
|
||||
avec les valeurs affichées : régression 564/564, qualité 22/22, recette 15/15.
|
||||
- Liens Markdown de ce rapport résolus vers des cibles existantes (pré-vérifiés).
|
||||
|
||||
## Non fait (hors périmètre worker · touche au VPS)
|
||||
- Déploiement production réel (bench migrate, import fixtures, câblage nginx/systemd,
|
||||
builds stores, indexation SEO, voix Amélie) → **VPS `153.75.250.214`** · agents
|
||||
DevOps/ERPNext, plan ordonné dans `devops/deploy_runbook` (`CLAUDE.md` #8).
|
||||
- Enregistrement `act_runner` Gitea + exécution serveur de la baseline Playwright.
|
||||
|
||||
## Note de convention (réconciliation doc-vs-réalité)
|
||||
Deux canaux de journalisation coexistent et sont désormais explicités :
|
||||
1. **`05_activity_log/YYYY-MM-DD.md`** — journal **technique par session** (riche,
|
||||
tenu à chaque session · instruction mandat #6). **Canal courant de facto.**
|
||||
2. **`05_deliverables_mvp/daily_reports/YYYY-MM-DD.md`** — **instantané consolidé
|
||||
stakeholder** (roadmap §Escalations). Repris ici après lapsus depuis `2026-07-30`.
|
||||
Les deux servent des lecteurs différents (technique vs. direction) et ne sont **pas
|
||||
des doublons**. Un lecteur d'`AGENT.md` cherchant « le journal récent » doit se
|
||||
référer au **canal 1** pour le détail par session, au **canal 2** pour la synthèse.
|
||||
|
||||
## Prochaine tâche suggérée
|
||||
- Maintenir le canal `daily_reports/` à jour à chaque session buffer (1 instantané/jour).
|
||||
- Poursuivre l'audit d'exactitude des 11 fiches `AGENT.md` restantes (mêmes contrôles
|
||||
que `crm`/`bim` ci-dessus) — repérer toute sur-promesse d'artefact ou compte périmé.
|
||||
- Buffer : ne durcir un gate que si un **blind-spot est prouvé par mutation-test**
|
||||
(mémoire `verify-uncovered-before-gating`), jamais un gate redondant (#5).
|
||||
|
||||
---
|
||||
|
||||
**Auto-score 4Big de la sweep de vérification : 96/100.** Réserve −4 : audit
|
||||
d'exactitude limité à 2 des 13 fiches cette session (les 11 autres restent à
|
||||
re-vérifier) ; déploiement serveur hors périmètre (VPS). État launch-readiness
|
||||
confirmé et **intégralement sourcé** : 22/22 qualité · 564/564 régression · 15/15
|
||||
recette · 7 gates verts.
|
||||
|
||||
---
|
||||
|
||||
## Clôture de journée · addendum session `20260802_120544`
|
||||
|
||||
> Cet addendum est **additif** : le corps ci-dessus reste le compte-rendu horodaté
|
||||
> de la session `110539` (record historique intact). Il **acte la clôture** de la
|
||||
> campagne d'audit que ce même rapport listait en « Prochaine tâche suggérée #2 »,
|
||||
> réalisée plus tard le même jour, et **lève la réserve −4** devenue caduque.
|
||||
|
||||
**Ce qui a fermé depuis 11:11** — l'**audit d'exactitude doc-vs-réalité des 11
|
||||
fiches `AGENT.md` restantes** (devops · erpnext_backend · faisabilite ·
|
||||
frontend_console · ifc_speckle · mobile · onapi_legal · publiciste · qa · rendu ·
|
||||
seo) a été mené à terme (commit `2bc3afb`, session `113542`) : **0 dérive réelle**.
|
||||
Les 2 « dérives » remontées par les agents ont été **levées comme faux positifs de
|
||||
convention**, prouvés avant toute action (mémoire `verify-uncovered-before-gating`) :
|
||||
- **onapi_legal** — chemins backtick `../rbac/…` / `../crm/workflow_vente/…` **relatifs
|
||||
à l'arbre des livrables** (`05_deliverables_mvp/legal/`), **miroir du code** du
|
||||
générateur, pas fiche-relatifs ; code-spans volontairement non link-checkés
|
||||
(mémoire `backtick-path-escapes-check-docs`).
|
||||
- **faisabilite** — chemins `/opt/oto/…`, version `{X}`, section « Composants à
|
||||
créer » : **VPS-runtime assumés**, hors périmètre worker (#8), déjà réconciliés
|
||||
§15-17 / §27-29 ; seule retouche = **note de lisibilité** (bandeau VPS-runtime vs
|
||||
template committé), zéro chiffre.
|
||||
|
||||
**Bilan de la campagne (levée de la réserve −4)** — les **13/13 fiches**
|
||||
`03_agents/*/AGENT.md` sont désormais **auditées exactes** (crm/bim en session
|
||||
`110539` + les 11 ici). Classe close : mémoire `fiche-accuracy-audit-closed`.
|
||||
|
||||
**État courant re-vérifié à la clôture** (recompute indépendant `python3` sur les
|
||||
artefacts commités · aucun chiffre saisi à la main) — **inchangé et vert** :
|
||||
|
||||
| Dimension | Valeur | Verdict | Source |
|
||||
|---|---|---|---|
|
||||
| Qualité 4Big | **22/22 modules** (seuil `pass_score` 95) | `PASS` | `qa/audit_4big/out/quality_report.json` |
|
||||
| Régression (run) | **22 suites · 564 ran · 564 passés · 0 échec · 0 erreur** | `PASS` | `qa/regression/out/regression_run.json` |
|
||||
| Recette roadmap | **15 promesses** `in_repo` | `true` | `qa/acceptance/out/acceptance_matrix.json` |
|
||||
| Fiches agents | **13/13 auditées exactes** | — | `03_agents/*/AGENT.md` |
|
||||
| Gates CI | **7 gates** re-joués → **exit 0** + reproductibilité `out/` byte-identique | vert | `ci/README.md` |
|
||||
|
||||
**Prochaine tâche (révisée)** — la file d'audit fiches est **vide** (13/13 clos). Le
|
||||
buffer Sprint 8 reste en posture de **veille** : maintenir `daily_reports/` (1
|
||||
instantané/jour), et ne durcir un gate **que si** un blind-spot est **prouvé par
|
||||
mutation-test** (`verify-uncovered-before-gating`), jamais un gate redondant (#5).
|
||||
|
||||
**Auto-score 4Big de la clôture : 97/100.** Réserve −3 : purement une passe de
|
||||
**vérification + réconciliation de reporting** (aucun nouveau livrable — attendu en
|
||||
phase buffer saturée) ; déploiement serveur hors périmètre (VPS · #8).
|
||||
|
||||
---
|
||||
|
||||
## Fin de journée · addendum session `20260802_143555`
|
||||
|
||||
> **Additif** (comme l'addendum précédent) : le corps et l'addendum de clôture
|
||||
> restent intacts. Cet ajout **consolide les 4 sessions buffer intercalées entre la
|
||||
> clôture `120544` et 14:35** (commits `cb8d931` · `8dcedb0` · `576e78b` · `bd3572b`),
|
||||
> absentes de l'instantané stakeholder alors que leur trace fine existe déjà au canal 1
|
||||
> ([`05_activity_log/2026-08-02.md`](../../05_activity_log/2026-08-02.md)). Tenir le
|
||||
> canal 2 à jour à chaque session buffer était la **« Prochaine tâche » #1** de ce
|
||||
> rapport (l.84). Chaque chiffre ci-dessous est **re-vérifié contre l'artefact commité**
|
||||
> (recompute `python3` indépendant · anti-invention `CLAUDE.md` #6 · zéro donnée nouvelle).
|
||||
|
||||
**Les 4 sessions consolidées** — toutes en posture buffer (aucun nouveau module ·
|
||||
contrainte « pas d'invention de modules ») :
|
||||
- **`123546` (`cb8d931`)** — *dérive doc-vs-réalité corrigée* : les 2 docs de mandat de
|
||||
tête (`AGENTS_EXISTING_ASSETS` titre + `MASTER_PROMPT §28`) disaient « **12 agents** »
|
||||
alors que le **13ᵉ** (publiciste) est livré+gaté → correction **12→13** (source unique
|
||||
`03_agents/`) + clarification du statut publiciste (**LIVRÉ** mandat · runtime VPS hors
|
||||
#8) + extension de `check_readme_claims` (réutilise `n_agents`) pour ancrer ces 2 docs.
|
||||
- **`130548` (`8dcedb0`)** — *ancrage anti-dérive* : les 3 surfaces vives de
|
||||
`GAP_ANALYSIS_SPRINT1` citant le compte d'agents (dont la coche de couverture DoD) sont
|
||||
ré-ancrées sur `n_agents` (re-dérivé, jamais une liste à la main).
|
||||
- **`133549` (`576e78b`)** — *enquête anti-dérive, ZÉRO gate ajouté (#5)* : le `roles_couverts`
|
||||
(« 44 ») des 3 manifestes s'est révélé **transitivement mono-sourcé** (même fonction
|
||||
`roles_by_portail` sur l'unique contrat `rbac_50_roles.json`) → un cross-gate serait
|
||||
**redondant** ; garde-fou documenté dans [`ci/README.md`](../../ci/README.md) pour
|
||||
prévenir un gate N+1 inutile.
|
||||
- **`140554` (`bd3572b`)** — *audit d'EFFICACITÉ des gates, ZÉRO gate ajouté (#5)* :
|
||||
**mutation-testing** du suite (7 mutations ciblées sur 4 gates à oracle recomputé) →
|
||||
**7/7 ROUGE** prouvés (« vert » ≠ « faux-vert »). Confirme que le suite **mord**
|
||||
réellement en phase de bascule launch.
|
||||
|
||||
**État courant MVP · re-vérifié à 14:35 · 100 % sourcé** (recompute `python3` indépendant
|
||||
sur les artefacts commités · aucun chiffre saisi à la main) — **inchangé et vert** :
|
||||
|
||||
| Dimension | Valeur | Verdict | Source commitée |
|
||||
|---|---|---|---|
|
||||
| Qualité 4Big | **22/22 modules à 100/100** (seuil `pass_score` **95** · #5) | `PASS` | [`qa/audit_4big/out/quality_report.json`](../qa/audit_4big/out/quality_report.json) |
|
||||
| Régression (run) | **22 suites · 564 ran · 564 passés · 0 échec · 0 erreur** | `PASS` | [`qa/regression/out/regression_run.json`](../qa/regression/out/regression_run.json) |
|
||||
| Recette roadmap | **15/15 promesses** `status=in_repo` | `true` | [`qa/acceptance/out/acceptance_matrix.json`](../qa/acceptance/out/acceptance_matrix.json) |
|
||||
| Fiches agents | **13/13 auditées exactes** (classe close) | — | `03_agents/*/AGENT.md` |
|
||||
| Gates CI | **7 gates statiques** re-joués → **exit 0** + reproductibilité `out/` byte-identique | vert | [`ci/README.md`](../../ci/README.md) |
|
||||
| Câblage CI | `gate.needs` = **30 jobs** agrégés · **1** seul job manuel (`e2e-baseline`) | intègre | [`.gitea/workflows/ci.yml`](../../.gitea/workflows/ci.yml) |
|
||||
|
||||
**Vérifications effectuées à la clôture** (en-repo, sans toucher au VPS) :
|
||||
- **7 gates CI → exit 0** sur l'arbre propre (`check_artifacts` · `check_ci_integrity` ·
|
||||
`check_docs` · `check_readme_claims` · `check_regression` · `guard_constraints` ·
|
||||
`validate_json`).
|
||||
- Recompute indépendant des agrégats concordant : **22/22** qualité (scores distincts =
|
||||
{100}) · **564/564** régression · **15/15** recette · **13** fiches · `gate.needs` = **30**.
|
||||
- Arbre `git status --porcelain` **vide** avant/après ; aucune commande touchant au VPS.
|
||||
|
||||
**Prochaine tâche (révisée)** — file d'audit fiches **vide** (13/13 clos), campagne de
|
||||
gates **saturée** (dernier audit d'efficacité 7/7 ROUGE). Le buffer Sprint 8 reste en
|
||||
**veille** : maintenir `daily_reports/` (1 instantané/jour · fait ici), et **ne durcir un
|
||||
gate que si un blind-spot est prouvé par mutation-test** (`verify-uncovered-before-gating`),
|
||||
jamais un gate redondant (#5). Déploiement production réel reste **hors périmètre worker**
|
||||
(VPS `153.75.250.214` · agents DevOps/ERPNext · #8).
|
||||
|
||||
**Auto-score 4Big de la consolidation : 97/100.** Réserve −3 : passe de
|
||||
**réconciliation de reporting** (canal 2 rattrapé sur 4 sessions · aucun nouveau
|
||||
livrable — attendu en buffer saturé) ; déploiement serveur hors périmètre (VPS · #8).
|
||||
État launch-readiness **inchangé et intégralement sourcé**.
|
||||
|
||||
## Fin de journée · addendum session `20260802_160601`
|
||||
|
||||
> **Additif** (3ᵉ, même convention que les deux précédents) : le corps et les deux
|
||||
> addenda restent intacts. Cet ajout consolide les **2 sessions buffer intercalées
|
||||
> entre l'addendum `143555` (14:35) et 15:36** (commits `49123ec` · `dcb463e`),
|
||||
> absentes de l'instantané stakeholder alors que leur trace fine existe au canal 1
|
||||
> ([`05_activity_log/2026-08-02.md`](../../05_activity_log/2026-08-02.md)). Tenir le
|
||||
> canal 2 à jour à chaque session buffer était la tâche de veille #1 de l'addendum
|
||||
> précédent (l.201). Chaque chiffre ci-dessous est **re-vérifié contre l'artefact
|
||||
> commité** (recompute `python3` indépendant · anti-invention `CLAUDE.md` #6 · zéro
|
||||
> donnée nouvelle).
|
||||
|
||||
**Les 2 sessions consolidées** — un seul livrable net, un **outil DevOps** (pas un
|
||||
nouveau module · contrainte « pas d'invention de modules » respectée) :
|
||||
- **`150601` (`49123ec`)** — *DevOps outillage : miroir LOCAL du gate CI* : ajout de
|
||||
[`run_ci.sh`](../../run_ci.sh) à la racine, qui **dérive** la liste des jobs de
|
||||
`gate.needs` dans [`.gitea/workflows/ci.yml`](../../.gitea/workflows/ci.yml) (zéro
|
||||
liste en dur · anti-dérive par construction · suit `ci.yml`) et rejoue les **30 jobs**
|
||||
(7 gates `ci/*.sh` + 23 suites module) en une commande. **PAS un gate (#5)** : la
|
||||
racine ∉ `ci/*.sh`, donc hors INV-B ; parseur `awk` anti-commentaire ; chemin d'échec
|
||||
prouvé (`EXIT=1` + dump). Doc `README` + `ci/README`. Consigné en mémoire
|
||||
(*local-ci-runner*).
|
||||
- **`153601` (`dcb463e`)** — *durcissement du même outil* : le décompte **30/23/7** du
|
||||
commentaire d'en-tête, jusque-là **figé** (risque de dérive silencieuse si `ci.yml`
|
||||
gagne/perd un job), est retiré et **DÉRIVÉ à l'exécution** — la valeur affichée par
|
||||
`run_ci.sh` provient désormais du parse de `gate.needs`, jamais d'un nombre saisi.
|
||||
|
||||
**État courant MVP · re-vérifié à 16:06 · 100 % sourcé** (recompute `python3` indépendant
|
||||
sur les artefacts commités · aucun chiffre saisi à la main) — **inchangé et vert** :
|
||||
|
||||
| Dimension | Valeur | Verdict | Source commitée |
|
||||
|---|---|---|---|
|
||||
| Qualité 4Big | **22/22 modules à 100/100** (scores distincts = {100} · seuil 95 · #5) | `PASS` | [`qa/audit_4big/out/quality_report.json`](../qa/audit_4big/out/quality_report.json) |
|
||||
| Régression (run) | **22 suites · 564 ran · 564 passés · 0 échec · 0 erreur · 0 skip** | `PASS` | [`qa/regression/out/regression_run.json`](../qa/regression/out/regression_run.json) |
|
||||
| Recette roadmap | **15/15 promesses** `status=in_repo` | `true` | [`qa/acceptance/out/acceptance_matrix.json`](../qa/acceptance/out/acceptance_matrix.json) |
|
||||
| Fiches agents | **13/13 auditées exactes** (classe close) | — | `03_agents/*/AGENT.md` |
|
||||
| Câblage CI | `gate.needs` = **30 jobs** (7 gates `ci/*.sh` + 23 suites module) | intègre | [`.gitea/workflows/ci.yml`](../../.gitea/workflows/ci.yml) |
|
||||
| Miroir local | `run_ci.sh` rejoue le gate → **30 PASS · 0 FAIL · 0 SKIP** | vert | [`run_ci.sh`](../../run_ci.sh) |
|
||||
|
||||
**Vérifications effectuées à la clôture** (en-repo, sans toucher au VPS) :
|
||||
- **`run_ci.sh` → 30 PASS · 0 FAIL · 0 SKIP** (miroir complet du gate, décompte 30/7/23
|
||||
dérivé à l'exécution de `gate.needs`).
|
||||
- Recompute indépendant des agrégats concordant : **22/22** qualité (scores = {100}) ·
|
||||
**564/564** régression · **15/15** recette (verdict `true`) · **13** fiches ·
|
||||
`gate.needs` = **30**.
|
||||
- Arbre `git status --porcelain` **vide** avant l'édition ; aucune commande touchant au VPS.
|
||||
|
||||
**Prochaine tâche (inchangée)** — buffer Sprint 8 en **veille saturée** : file d'audit
|
||||
fiches **vide** (13/13 clos), campagne de gates **saturée**. Maintenir `daily_reports/`
|
||||
à chaque session (fait ici), et **ne durcir un gate que si un blind-spot est prouvé par
|
||||
mutation-test** (*verify-uncovered-before-gating*), jamais un gate redondant (#5).
|
||||
Déploiement production réel reste **hors périmètre worker** (VPS `153.75.250.214` · #8).
|
||||
|
||||
**Auto-score 4Big de la consolidation : 97/100.** Réserve −3 : passe de
|
||||
**réconciliation de reporting** (canal 2 rattrapé sur 2 sessions · le seul livrable net
|
||||
est l'outil DevOps `run_ci.sh`, déjà gaté par construction — attendu en buffer saturé) ;
|
||||
déploiement serveur hors périmètre (VPS · #8). État launch-readiness **inchangé et
|
||||
intégralement sourcé**.
|
||||
|
||||
## Fin de journée · addendum session `20260802_180604`
|
||||
|
||||
> **Additif** (4ᵉ, même convention que les trois précédents) : le corps et les trois
|
||||
> addenda restent intacts. Cet ajout consolide les **3 sessions buffer intercalées entre
|
||||
> l'addendum `160601` (16:06) et 18:06** (commits `59eb4dc` · `68f8c1a` · `d2ab269`),
|
||||
> absentes de l'instantané stakeholder alors que leur trace fine existe au canal 1
|
||||
> ([`05_activity_log/2026-08-02.md`](../../05_activity_log/2026-08-02.md)). Tenir le
|
||||
> canal 2 à jour à chaque session buffer était la tâche de veille #1 de l'addendum
|
||||
> précédent (l.259). Chaque chiffre ci-dessous est **re-vérifié contre l'artefact
|
||||
> commité** (recompute `python3` indépendant · anti-invention `CLAUDE.md` #6 · zéro
|
||||
> donnée nouvelle).
|
||||
|
||||
**Les 3 sessions consolidées** — **aucun nouveau module, aucun gate ajouté (#5)** : trois
|
||||
retouches de **doc / outillage DevOps** dans la lignée directe de `run_ci.sh`, chacune
|
||||
une correction d'honnêteté (retrait de comptes figés) plutôt qu'un livrable net :
|
||||
- **`163601` (`59eb4dc`)** — *fiche `03_agents/devops/AGENT.md`* : documentation du
|
||||
livrable `run_ci.sh` (indexé au `README` racine mais absent de la fiche de son agent
|
||||
propriétaire) → 3ᵉ ligne de table + sous-section « outillage local, **PAS un gate #5** »
|
||||
(racine ∉ `ci/`, hors INV-B). Zéro module, zéro gate ; `check_docs` valide le lien
|
||||
`../../run_ci.sh`.
|
||||
- **`170601` (`68f8c1a`)** — *`run_ci.sh` : `-h|--help` + en-tête `--static` honnête*
|
||||
(UX du lanceur · **PAS un gate #5**) — le lanceur documente désormais son propre usage,
|
||||
toujours hors périmètre des gates.
|
||||
- **`173603` (`d2ab269`)** — *`ci/README.md` : retrait des comptes CI figés « 7 gates /
|
||||
23 suites »* (même fix d'honnêteté que `dcb463e`, un cran plus haut · anti-invention #6,
|
||||
**PAS un gate #5**) — le décompte exact reste **dérivé** par `run_ci.sh` de `gate.needs`,
|
||||
jamais re-transcrit à la main dans la prose.
|
||||
|
||||
**État courant MVP · re-vérifié à 18:06 · 100 % sourcé** (recompute `python3` indépendant
|
||||
sur les artefacts commités · aucun chiffre saisi à la main) — **inchangé et vert** :
|
||||
|
||||
| Dimension | Valeur | Verdict | Source commitée |
|
||||
|---|---|---|---|
|
||||
| Qualité 4Big | **22/22 modules à 100/100** (scores distincts = {100} · seuil 95 · #5) | `PASS` | [`qa/audit_4big/out/quality_report.json`](../qa/audit_4big/out/quality_report.json) |
|
||||
| Régression (run) | **22 suites · 564 ran · 564 passés · 0 échec · 0 erreur · 0 skip** | `PASS` | [`qa/regression/out/regression_run.json`](../qa/regression/out/regression_run.json) |
|
||||
| Recette roadmap | **15/15 promesses** `status=in_repo` | `true` | [`qa/acceptance/out/acceptance_matrix.json`](../qa/acceptance/out/acceptance_matrix.json) |
|
||||
| Fiches agents | **13/13 auditées exactes** (classe close) | — | `03_agents/*/AGENT.md` |
|
||||
| Câblage CI | `gate.needs` = **30 jobs** (7 gates `ci/*.sh` + 23 suites module) | intègre | [`.gitea/workflows/ci.yml`](../../.gitea/workflows/ci.yml) |
|
||||
| Miroir local | `run_ci.sh` rejoue le gate → **30 PASS · 0 FAIL · 0 SKIP** | vert | [`run_ci.sh`](../../run_ci.sh) |
|
||||
|
||||
**Vérifications effectuées à la clôture** (en-repo, sans toucher au VPS) :
|
||||
- **`run_ci.sh` → 30 PASS · 0 FAIL · 0 SKIP** (miroir complet du gate, décompte 30/7/23
|
||||
dérivé à l'exécution de `gate.needs`).
|
||||
- Recompute indépendant des agrégats concordant : **22/22** qualité (scores = {100}) ·
|
||||
**564/564** régression · **15/15** recette (verdict `true`) · **13** fiches ·
|
||||
`gate.needs` = **30**.
|
||||
- Arbre `git status --porcelain` **vide** avant l'édition ; aucune commande touchant au VPS.
|
||||
|
||||
**Prochaine tâche (inchangée)** — buffer Sprint 8 en **veille saturée** : file d'audit
|
||||
fiches **vide** (13/13 clos), campagne de gates **saturée**, audit doc-vs-réalité relancé
|
||||
cette session → **aucune dérive** trouvée. Maintenir `daily_reports/` à chaque session
|
||||
(fait ici), et **ne durcir un gate que si un blind-spot est prouvé par mutation-test**
|
||||
(*verify-uncovered-before-gating*), jamais un gate redondant (#5). Déploiement production
|
||||
réel reste **hors périmètre worker** (VPS `153.75.250.214` · #8).
|
||||
|
||||
**Auto-score 4Big de la consolidation : 97/100.** Réserve −3 : passe de
|
||||
**réconciliation de reporting** (canal 2 rattrapé sur 3 sessions de retouches doc/outillage,
|
||||
aucun livrable net nouveau — attendu en buffer saturé) ; déploiement serveur hors périmètre
|
||||
(VPS · #8). État launch-readiness **inchangé et intégralement sourcé**.
|
||||
@@ -114,7 +114,9 @@ def _check_derived_arithmetic(brief: dict, manifest: dict) -> list[str]:
|
||||
"""Reproduit indépendamment les 4 agrégats et compare au manifeste.
|
||||
|
||||
Prouve qu'aucune valeur calculée n'a été « posée » : elle DOIT découler des
|
||||
typologies sourcées et du taux canonique 52 %.
|
||||
typologies sourcées et du taux canonique de point d'équilibre. Ce taux est lu
|
||||
à la SOURCE UNIQUE (`CANONICAL` · CLAUDE.md #9, gaté), jamais recopié en dur
|
||||
ici — sinon un changement du mandat (#9) casserait cet oracle en silence.
|
||||
"""
|
||||
motifs: list[str] = []
|
||||
rows = finance.typologies(brief)
|
||||
@@ -128,8 +130,9 @@ def _check_derived_arithmetic(brief: dict, manifest: dict) -> list[str]:
|
||||
if all_q and all(r["prix_usd"] is not None for r in rows) else None)
|
||||
exp_dop = (sum(q * r["prix_dop"] for q, r in zip(qtes, rows))
|
||||
if all_q and all(r["prix_dop"] is not None for r in rows) else None)
|
||||
exp_pe = (float(math.ceil(0.52 * exp_total))
|
||||
if exp_total is not None else None)
|
||||
pe_pct = finance._pct(deps.CANONICAL["point_equilibre_pct"])
|
||||
exp_pe = (float(math.ceil(pe_pct * exp_total))
|
||||
if exp_total is not None and pe_pct is not None else None)
|
||||
|
||||
for cle, exp in (("total_unites", exp_total),
|
||||
("valeur_catalogue_usd", exp_usd),
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"required": ["projet"],
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"projet": { "type": "string", "pattern": "^P0[1-9]$" },
|
||||
"projet": { "type": "string", "pattern": "^P0[1-9]$", "description": "Code projet canonique (P01..P09) · domaine ancré sur CLAUDE.md §Projets." },
|
||||
"nom": { "type": "string" },
|
||||
"synthetique": { "type": "boolean", "description": "true = fixture de test, jamais publiable." },
|
||||
"sources": {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"projet": {
|
||||
"type": "string",
|
||||
"pattern": "^P0[1-9]$",
|
||||
"description": "Code projet canonique (P01..P09)."
|
||||
"description": "Code projet canonique (P01..P09) · domaine ancré sur CLAUDE.md §Projets."
|
||||
},
|
||||
"template_version": {
|
||||
"type": "string",
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"generated_from": "rbac_50_roles.json (permissions_cibles + portail par rôle)",
|
||||
"spec_version": "1.0.0",
|
||||
"source_version": "1.0.0",
|
||||
"roadmap_ref": "04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md · Sprint 4 l.49 « Frontend Console : 5 portails (Ventes/Construction/Achat/Compta/Direction) »",
|
||||
"counts": {
|
||||
"workspaces": 5,
|
||||
"roles_couverts": 44,
|
||||
"liens_total": 53,
|
||||
"raccourcis_total": 20
|
||||
},
|
||||
"brand": {
|
||||
"note": "Tokens de marque luxury dark+doré (CLAUDE.md #4). Appliqués par la couche thème desk (Website Theme / CSS custom) déposée par l'agent Frontend sur le VPS — HORS de ce worker (#8). Repris ici pour le hand-off, jamais fabriqués.",
|
||||
"fond": {
|
||||
"valeur": "#0a0a12",
|
||||
"source": "CLAUDE.md #4"
|
||||
},
|
||||
"accent": {
|
||||
"valeur": "#f0b429",
|
||||
"source": "CLAUDE.md #4"
|
||||
},
|
||||
"polices": [
|
||||
{
|
||||
"valeur": "Fraunces",
|
||||
"source": "CLAUDE.md #4"
|
||||
},
|
||||
{
|
||||
"valeur": "Cormorant Garamond",
|
||||
"source": "CLAUDE.md #4"
|
||||
}
|
||||
]
|
||||
},
|
||||
"module_note": "Workspace.module laisse a None (a_confirmer) : l'agent ERPNext Backend le fixe au module de l'app OTO a l'import (#8). Le worker ne fabrique pas de nom d'app.",
|
||||
"doctypes_custom_a_creer": [
|
||||
"CONFOTUR Application",
|
||||
"Faisabilité",
|
||||
"Publiciste Log"
|
||||
],
|
||||
"workspaces": [
|
||||
{
|
||||
"portail": "ventes",
|
||||
"workspace": "OTO Ventes",
|
||||
"nb_cartes": 4,
|
||||
"nb_raccourcis": 4,
|
||||
"nb_liens": 11,
|
||||
"nb_roles": 12,
|
||||
"doctypes_custom": [
|
||||
"CONFOTUR Application",
|
||||
"Publiciste Log"
|
||||
]
|
||||
},
|
||||
{
|
||||
"portail": "construction",
|
||||
"workspace": "OTO Construction",
|
||||
"nb_cartes": 4,
|
||||
"nb_raccourcis": 4,
|
||||
"nb_liens": 9,
|
||||
"nb_roles": 10,
|
||||
"doctypes_custom": [
|
||||
"Faisabilité"
|
||||
]
|
||||
},
|
||||
{
|
||||
"portail": "achat",
|
||||
"workspace": "OTO Achat",
|
||||
"nb_cartes": 3,
|
||||
"nb_raccourcis": 4,
|
||||
"nb_liens": 8,
|
||||
"nb_roles": 5,
|
||||
"doctypes_custom": []
|
||||
},
|
||||
{
|
||||
"portail": "compta",
|
||||
"workspace": "OTO Compta",
|
||||
"nb_cartes": 4,
|
||||
"nb_raccourcis": 4,
|
||||
"nb_liens": 11,
|
||||
"nb_roles": 8,
|
||||
"doctypes_custom": []
|
||||
},
|
||||
{
|
||||
"portail": "direction",
|
||||
"workspace": "OTO Direction",
|
||||
"nb_cartes": 4,
|
||||
"nb_raccourcis": 4,
|
||||
"nb_liens": 14,
|
||||
"nb_roles": 9,
|
||||
"doctypes_custom": [
|
||||
"CONFOTUR Application",
|
||||
"Faisabilité"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
# Actifs existants OTOV7 · Mapping vers les 12 agents DTP
|
||||
# Actifs existants OTOV7 · Mapping vers les 13 agents DTP
|
||||
|
||||
## Principe : NE PAS REPARTIR DE ZÉRO
|
||||
Chaque agent hérite/réutilise les modules déjà présents avant de créer du nouveau code.
|
||||
@@ -112,9 +112,16 @@ Chaque agent hérite/réutilise les modules déjà présents avant de créer du
|
||||
4. **Capabilities OTOIA** = fondation → chaque agent DTP branche dessus
|
||||
5. **Éliminer le vieux** : si un module est obsolète, l'archiver dans `_ARCHIVES/`, ne pas laisser deux versions
|
||||
|
||||
## 13. Publiciste Agent — NOUVEAU (à créer)
|
||||
## 13. Publiciste Agent — NOUVEAU
|
||||
**Rôle** : Maintient automatiquement le site public `vente.otov7.com` à partir des faisabilités.
|
||||
|
||||
> **Statut mandat** : la fiche + le générateur déterministe côté dépôt sont **LIVRÉS**
|
||||
> ([`03_agents/publiciste/AGENT.md`](03_agents/publiciste/AGENT.md) ·
|
||||
> [`05_deliverables_mvp/publiciste/`](05_deliverables_mvp/publiciste/README.md), gated
|
||||
> 100/100 · suite de régression `publiciste`). La liste **« À développer »** ci-dessous
|
||||
> recense le **runtime VPS** (orchestrateur `publiciste.py`, triggers systemd/inotify,
|
||||
> notifications WhatsApp) qui reste hors périmètre worker (`CLAUDE.md` #8).
|
||||
|
||||
**Ressources existantes à réutiliser** :
|
||||
- `/opt/oto/config/projets_config.json` (déjà en place)
|
||||
- `/opt/oto/config/projets_editor.py` (API GET/POST déjà en place)
|
||||
|
||||
@@ -23,6 +23,7 @@ NON-NÉGOCIABLES : [`CLAUDE.md`](CLAUDE.md).
|
||||
| [`05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md`](05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md) | Audit d'assets + gap analysis (Sprint 1) |
|
||||
| [`05_activity_log/`](05_activity_log) | Journal de session horodaté |
|
||||
| [`.gitea/workflows/ci.yml`](.gitea/workflows/ci.yml) · [`ci/`](ci/README.md) | Gate CI Gitea Actions + guards locaux |
|
||||
| [`run_ci.sh`](run_ci.sh) | Miroir **local** du gate : rejoue tout `gate.needs` (dérivé de ci.yml, sans liste en dur) |
|
||||
| [`tests/`](tests) | Baseline E2E Playwright |
|
||||
|
||||
## Les 13 agents
|
||||
@@ -40,9 +41,11 @@ Transverses : [`devops`](03_agents/devops/AGENT.md) · [`qa`](03_agents/qa/AGENT
|
||||
|
||||
- **Qualité 4Big** : **22/22 modules gated à 100/100** (seuil 95 · `CLAUDE.md` #5), verdict `PASS`
|
||||
— source [`qa/audit_4big/out/quality_report.json`](05_deliverables_mvp/qa/audit_4big/out/quality_report.json).
|
||||
- **Régression** : **22 suites gated** couvertes bijectivement vs CI ; le compte de tests
|
||||
agrégé faisant autorité est produit par `qa/regression run` (non commité par design)
|
||||
— plan [`qa/regression/out/regression_plan.json`](05_deliverables_mvp/qa/regression/out/regression_plan.json).
|
||||
- **Régression** : **22 suites gated** couvertes bijectivement vs CI. Le **compte de tests
|
||||
agrégé faisant autorité** vit dans [`qa/regression/out/regression_run.json`](05_deliverables_mvp/qa/regression/out/regression_run.json),
|
||||
artefact **commité et byte-gaté** : `ci/check_regression.sh` régénère un `run` frais et exige
|
||||
l'identité **byte-for-byte** avec la baseline commitée (verdict `PASS`). Recensement déterministe
|
||||
des suites : [`qa/regression/out/regression_plan.json`](05_deliverables_mvp/qa/regression/out/regression_plan.json).
|
||||
- **Recette roadmap** : **15 promesses** (8 livrables sprint + 7 métriques MVP), **15 `in_repo`
|
||||
prouvées** (chacune traçant ses items hors-périmètre worker · #8 · ex. M5 « app publiée 2 stores »),
|
||||
verdict `true` — source [`qa/acceptance/out/acceptance_matrix.json`](05_deliverables_mvp/qa/acceptance/out/acceptance_matrix.json).
|
||||
|
||||
+176
-4
File diff suppressed because one or more lines are too long
+2756
-4
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================================
|
||||
# run_ci.sh · OTO Enterprise OS DTP · miroir LOCAL du gate CI
|
||||
# ----------------------------------------------------------------------------
|
||||
# Reproduit en une commande, EN LOCAL, exactement l'ensemble de checks que le
|
||||
# gate de merge Gitea Actions agrège — sans runner, sans réseau (Sprint 8 ·
|
||||
# DevOps « monitoring / regression exhaustifs »).
|
||||
#
|
||||
# POURQUOI ce script existe : chaque session rejouait à la main une boucle
|
||||
# ad-hoc « for g in guard_constraints validate_json … ; do bash ci/$g.sh ». Une
|
||||
# telle liste écrite à la main DÉRIVE en silence de ce que la CI enforce
|
||||
# réellement (un gate ajouté/retiré dans `.gitea/workflows/ci.yml` n'y était
|
||||
# jamais répercuté) — la même classe de « vert trompeur » que les gates du
|
||||
# dépôt traquent. Ce script n'a AUCUNE liste en dur : il DÉRIVE la liste des
|
||||
# checks depuis `gate.needs` de ci.yml (la source de vérité que
|
||||
# `ci/check_ci_integrity.sh` verrouille déjà) et exécute, pour chaque job, la
|
||||
# commande `run:` que ci.yml déclare, dans son `working-directory:`. Il ne peut
|
||||
# donc ni oublier ni inventer un check : ajouter un gate à la CI le fait
|
||||
# apparaître ici automatiquement, zéro édition.
|
||||
#
|
||||
# PÉRIMÈTRE : uniquement les jobs de `gate.needs` — ce qui exclut, par
|
||||
# construction et à dessein, les jobs manuels `workflow_dispatch` hors gate
|
||||
# (ex. `e2e-baseline`/`npm test`, qui exige Node) et le job `gate` lui-même.
|
||||
# Les jobs restants sont tous soit `bash ci/*.sh` (gates statiques), soit
|
||||
# `python3 -m unittest` (suites de module) → stdlib pur, aucune install pip,
|
||||
# aucune commande touchant le VPS. Le décompte exact (jobs / gates / suites)
|
||||
# est DÉRIVÉ de gate.needs et imprimé à l'exécution — jamais figé dans ce
|
||||
# commentaire, où il se périmerait en silence (anti-invention CLAUDE.md #6).
|
||||
#
|
||||
# CE N'EST PAS un gate (aucun nouveau `ci/*.sh`, aucune nouvelle assertion) :
|
||||
# c'est un LANCEUR de commodité. Son exactitude est STRUCTURELLE (il exécute ce
|
||||
# que ci.yml déclare), pas une re-transcription à protéger — inutile donc d'y
|
||||
# adjoindre un gate N+1 (CLAUDE.md #5).
|
||||
#
|
||||
# Usage :
|
||||
# bash run_ci.sh # exécute tout gate.needs (miroir CI complet)
|
||||
# bash run_ci.sh --static # seulement les gates statiques ci/*.sh (rapide)
|
||||
# bash run_ci.sh --list # liste les jobs qui SERAIENT lancés, sans exécuter
|
||||
# bash run_ci.sh --help # affiche cette aide et sort
|
||||
#
|
||||
# Sortie : une ligne PASS/FAIL par job + un récapitulatif. Code de sortie 0 ssi
|
||||
# tous les jobs passent (identique à la sémantique du gate de merge).
|
||||
# ============================================================================
|
||||
set -uo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
run_ci.sh · miroir LOCAL du gate CI (dérivé de gate.needs, sans liste en dur).
|
||||
Rejoue en une commande, sans runner ni réseau, l'ensemble de checks que le gate
|
||||
de merge Gitea Actions agrège.
|
||||
|
||||
Usage :
|
||||
bash run_ci.sh exécute tout gate.needs (miroir CI complet)
|
||||
bash run_ci.sh --static seulement les gates statiques ci/*.sh (rapide)
|
||||
bash run_ci.sh --list liste les jobs qui SERAIENT lancés, sans exécuter
|
||||
bash run_ci.sh --help affiche cette aide et sort
|
||||
|
||||
Sortie : une ligne PASS/FAIL par job + un récapitulatif.
|
||||
Code de sortie : 0 ssi tous les jobs passent · 1 si un job échoue ·
|
||||
2 option inconnue · 3 hors checkout git / ci.yml illisible.
|
||||
EOF
|
||||
}
|
||||
|
||||
# --- aide : disponible AVANT toute résolution git (n'exige aucun checkout) ---
|
||||
case "${1:-}" in -h|--help) usage; exit 0 ;; esac
|
||||
|
||||
# --- racine du dépôt (marche depuis n'importe quel sous-dossier) -------------
|
||||
ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || {
|
||||
echo "run_ci.sh : hors d'un checkout git — impossible de localiser ci.yml." >&2
|
||||
exit 3
|
||||
}
|
||||
cd "$ROOT" || exit 3
|
||||
CI_YML=".gitea/workflows/ci.yml"
|
||||
[ -f "$CI_YML" ] || { echo "run_ci.sh : $CI_YML introuvable." >&2; exit 3; }
|
||||
|
||||
MODE="all"
|
||||
case "${1:-}" in
|
||||
--static) MODE="static" ;;
|
||||
--list) MODE="list" ;;
|
||||
"") MODE="all" ;;
|
||||
*) echo "run_ci.sh : option inconnue « $1 » (attendu : --static | --list | --help)" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
# --- parse ci.yml : gate.needs (ordre) + par job {working-directory, run} ----
|
||||
# Les commentaires de ligne sont retirés d'abord (un « working-directory: » ou
|
||||
# « bash ci/… » cité en commentaire ne doit JAMAIS être capturé). Émet, sur
|
||||
# stdout, une ligne par job de gate.needs : "<job>\t<wd|->\t<commande run>".
|
||||
parse_jobs() {
|
||||
awk '
|
||||
{ line=$0; sub(/^[[:space:]]*#.*$/, "", line) } # drop full-line comments
|
||||
/^jobs:[[:space:]]*$/ { inj=1 }
|
||||
# début d’un job : clé à exactement 2 espaces d’indentation
|
||||
inj && match(line, /^ ([a-z0-9_-]+):[[:space:]]*$/, m) { job=m[1]; next }
|
||||
# gate.needs : la liste des jobs bloquants (source de vérité)
|
||||
inj && job=="gate" && match(line, /needs:[[:space:]]*\[(.*)\]/, g) {
|
||||
n=split(g[1], a, ","); for (i=1;i<=n;i++){ gsub(/[[:space:]]/,"",a[i]); if(a[i]!="") needs[++nn]=a[i] }
|
||||
}
|
||||
inj && job!="" && match(line, /^[[:space:]]+working-directory:[[:space:]]*(.+)$/, w) { wd[job]=w[1] }
|
||||
# commande run: (avec un argument — écarte la clé « run: » nue de defaults)
|
||||
inj && job!="" && match(line, /[[:space:]]run:[[:space:]]+(.+)$/, r) { cmd[job]=r[1] }
|
||||
END {
|
||||
for (i=1;i<=nn;i++){ j=needs[i]; printf "%s\t%s\t%s\n", j, (j in wd ? wd[j] : "-"), (j in cmd ? cmd[j] : "") }
|
||||
}
|
||||
' "$CI_YML"
|
||||
}
|
||||
|
||||
mapfile -t ROWS < <(parse_jobs)
|
||||
[ "${#ROWS[@]}" -gt 0 ] || { echo "run_ci.sh : gate.needs vide ou illisible dans $CI_YML." >&2; exit 3; }
|
||||
|
||||
is_static() { case "$1" in bash\ ci/*) return 0 ;; *) return 1 ;; esac; }
|
||||
|
||||
# --- décompte DÉRIVÉ (jamais figé) : gates statiques ci/*.sh vs suites module -
|
||||
# Ventilé depuis les mêmes ROWS que l'exécution, donc toujours exact : ajouter
|
||||
# un job à gate.needs le reclasse ici automatiquement, zéro édition (#6).
|
||||
n_gates=0; n_suites=0
|
||||
for row in "${ROWS[@]}"; do
|
||||
IFS=$'\t' read -r _j _w _c <<<"$row"
|
||||
[ -n "$_c" ] || continue
|
||||
if is_static "$_c"; then n_gates=$((n_gates+1)); else n_suites=$((n_suites+1)); fi
|
||||
done
|
||||
n_jobs=$((n_gates + n_suites))
|
||||
|
||||
# --- --list : montre le plan, n’exécute rien --------------------------------
|
||||
if [ "$MODE" = "list" ]; then
|
||||
printf '%-28s %-42s %s\n' "JOB" "WORKING-DIR" "RUN"
|
||||
for row in "${ROWS[@]}"; do
|
||||
IFS=$'\t' read -r job wd cmd <<<"$row"
|
||||
printf '%-28s %-42s %s\n' "$job" "$wd" "$cmd"
|
||||
done
|
||||
printf -- '-- %d jobs dérivés de gate.needs : %d gates statiques ci/*.sh + %d suites de module.\n' \
|
||||
"$n_jobs" "$n_gates" "$n_suites"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- exécution ---------------------------------------------------------------
|
||||
LOGDIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$LOGDIR"' EXIT
|
||||
pass=0; fail=0; skip=0; failed_jobs=()
|
||||
echo "run_ci.sh · miroir du gate CI (mode=$MODE) · $(git rev-parse --short HEAD 2>/dev/null || echo '?')"
|
||||
if [ "$MODE" = "static" ]; then
|
||||
echo "gate.needs dérivé : $n_jobs jobs · mode --static → $n_gates gates ci/*.sh seuls ($n_suites suites de module ignorées)"
|
||||
else
|
||||
echo "gate.needs dérivé : $n_jobs jobs = $n_gates gates ci/*.sh + $n_suites suites de module"
|
||||
fi
|
||||
echo "------------------------------------------------------------------------"
|
||||
for row in "${ROWS[@]}"; do
|
||||
IFS=$'\t' read -r job wd cmd <<<"$row"
|
||||
[ -n "$cmd" ] || { printf ' SKIP %-28s (aucune commande run: dans ci.yml)\n' "$job"; skip=$((skip+1)); continue; }
|
||||
if [ "$MODE" = "static" ] && ! is_static "$cmd"; then continue; fi
|
||||
log="$LOGDIR/$job.log"
|
||||
if [ "$wd" = "-" ]; then dir="$ROOT"; else dir="$ROOT/$wd"; fi
|
||||
if ( cd "$dir" && eval "$cmd" ) >"$log" 2>&1; then
|
||||
printf ' PASS %-28s %s\n' "$job" "$cmd"; pass=$((pass+1))
|
||||
else
|
||||
printf ' FAIL %-28s %s\n' "$job" "$cmd"; fail=$((fail+1)); failed_jobs+=("$job")
|
||||
sed 's/^/ | /' "$log" | tail -n 12
|
||||
fi
|
||||
done
|
||||
|
||||
echo "------------------------------------------------------------------------"
|
||||
printf 'Récapitulatif : %d PASS · %d FAIL · %d SKIP\n' "$pass" "$fail" "$skip"
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
printf 'Jobs en échec : %s\n' "$(IFS=', '; echo "${failed_jobs[*]}")"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Tous les checks du gate franchis en local."
|
||||
exit 0
|
||||
Reference in New Issue
Block a user