[DTP-Worker 20260805_181325] Auto exec · session 20260805_181325
CI / Contraintes NON-NÉGOCIABLES (CLAUDE.md) (push) Has been cancelled
CI / Validation JSON (schémas Faisabilité) (push) Has been cancelled
CI / Qualité documentaire (liens + 4Big) (push) Has been cancelled
CI / Reproductibilité des artefacts out/ (build == commité) (push) Has been cancelled
CI / Fraîcheur matrice de régression (run == commité) (push) Has been cancelled
CI / Intégrité du câblage CI (gate agrège tout · gates statiques verrouillés) (push) Has been cancelled
CI / Intégrité des chiffres du README (valeur == artefact cité · (push) Has been cancelled
CI / Intégrité mobile-build.yml (gating portable · activation différée · (push) Has been cancelled
CI / Publiciste · parser + schéma + generator (unittest) (push) Has been cancelled
CI / RBAC · 50 rôles + schéma (unittest) (push) Has been cancelled
CI / Faisabilité · générateur 4 volets + round-trip (unittest) (push) Has been cancelled
CI / RBAC · fixtures ERPNext (Role + Custom DocPerm) (push) Has been cancelled
CI / RBAC · plan User Permission (row-level) (push) Has been cancelled
CI / RBAC · Role Profile (bundles par portail) (push) Has been cancelled
CI / RBAC · run-book d'application unifié (agrégat 3 volets) (push) Has been cancelled
CI / Faisabilité · dossier bancable trilingue FR/EN/ES (push) Has been cancelled
CI / CRM · workflow vente ERPNext (lead → CONFOTUR) (push) Has been cancelled
CI / CRM · DocType porteur OTO Dossier Vente (push) Has been cancelled
CI / CRM · barème commissions vendeurs (push) Has been cancelled
CI / CRM · Financement Bancaire (gate hypothécaire RD) (push) Has been cancelled
CI / Fiscal · e-CF DGII (Compupar) (push) Has been cancelled
CI / Frontend · Workspaces 5 portails rôle (push) Has been cancelled
CI / Legal · DocType CONFOTUR Application (push) Has been cancelled
CI / QA · Audit 5D conformité (push) Has been cancelled
CI / SEO · mots-clés trilingues + schema.org + hreflang (push) Has been cancelled
CI / Chat OTOIA · montage par portail (Custom Block) (push) Has been cancelled
CI / QA · Audit 4Big (95+/100 sur 100% deliverables) (push) Has been cancelled
CI / Démo · Scénarios (run-sheet P07 banquier / P05 client) (push) Has been cancelled
CI / QA · Matrice de régression exhaustive (Sprint 8) (push) Has been cancelled
CI / DevOps · Run-book de déploiement VPS unifié (Sprint 8) (push) Has been cancelled
CI / QA · Matrice d'acceptation / traçabilité MVP (Sprint 8) (push) Has been cancelled
CI / Mobile · config app Expo/EAS (navigation par rôle) (push) Has been cancelled
CI / PIE · manifest de dépendances (Annexe 12 · V10.1) (push) Has been cancelled
CI / E2E baseline Playwright (manuel) (push) Has been cancelled
CI / Gate qualité (agrégat) (push) Has been cancelled

This commit is contained in:
Claude Code DTP Worker
2026-08-05 18:28:26 +00:00
parent 1441693e25
commit 1a44dfe1c0
5 changed files with 115 additions and 1 deletions
+15
View File
@@ -9,6 +9,21 @@
# ============================================================================
name: CI
# Mode UTF-8 forcé pour TOUS les jobs (builds + suites + gates) — indépendance
# LOCALE du runner. Chaque générateur clôt son `build` par un print(✅ / accents
# français) vers stdout, dont l'encodage suit la locale. Sur un runner à locale
# ASCII (image minimale : LC_ALL=C sans coercition PEP 538, PYTHONUTF8 non posé),
# ce print lève UnicodeEncodeError APRÈS écriture des fichiers → `check-artifacts`
# voit un exit non-nul (« build a échoué ») et les 25 suites plantent : tout le
# gate passe ROUGE en silence le jour où l'image runner change, alors qu'il est
# VERT sur le poste dev (UTF-8) — classe « le runner n'est pas ton poste ».
# PYTHONUTF8=1 (PEP 540) impose stdout/stdin/défaut-fichier en UTF-8 partout,
# indépendamment de LANG/LC_ALL → tous les jobs deviennent locale-robustes.
# Verrouillé par ci/check_ci_integrity.sh (INV-C) pour ne pas disparaître en
# silence. Miroir local : run_ci.sh exporte la même variable.
env:
PYTHONUTF8: "1"
on:
push:
branches: [main]
+55
View File
@@ -1,5 +1,60 @@
# Activity Log · 2026-08-05 · Claude Code DTP Worker
## Session 181325 · FIX RÉEL défaut locale-runner : le gate est ROUGE en silence sous locale ASCII → **VERROUILLÉ UTF-8**
**Choix de tâche.** `./run_ci.sh` au démarrage = **33 PASS**, arbre propre, roadmap
`ROADMAP_8_WEEKS_OR_LESS.md` **intégralement livrée/gatée in-repo** : les 15 promesses de
l'`acceptance_matrix` sont **toutes `status=in_repo`**, chaque reste (BIM runtime, builds EAS,
dépôts ONAPI, déploiement prod) explicitement `out_of_scope` VPS (#8). Un fan-out Explore
docstring-vs-code / prose-vs-numérique sur les livrables → **0 dérive** (repo propre). J'ai donc
attaqué un **axe de robustesse absent de la mémoire** et, contrairement aux 3 sweeps déterministes
précédents (hash-seed / locale-TZ / forward-compat, tous **CLEAN → attestation**), celui-ci a
révélé un **défaut RÉEL présent**.
**La faille — la coercition PEP 538 masquait le vrai cas.** Le sweep locale-TZ (`154314`) a rejoué
les builds sous `LANG=C`, mais Python **coerce silencieusement `C` → `C.UTF-8`** (PEP 538) : sous
`LANG=C` seul, `getpreferredencoding()` = **UTF-8** → le mode d'échec ASCII n'a **jamais été
exercé**. En neutralisant la coercition (`PYTHONUTF8=0 PYTHONCOERCECLOCALE=0 LC_ALL=C`),
l'encodage par défaut redevient **`ANSI_X3.4-1968` (ASCII)** — la config d'un **runner minimal**.
**Constat — 20 des 21 générateurs `build` PLANTENT.** Réplique de la boucle `check_artifacts` sous
locale ASCII neutralisée : **20/21 builds crashent** (`UnicodeEncodeError`), les 25 suites
échouent aussi. Cause : chaque générateur clôt `cmd_build` par un `print("✅ Bundle … généré" /
accents)` vers **stdout**, dont l'encodage suit la locale. Les fichiers sont écrits sans souci
(`encoding='utf-8'` explicite partout : 37 writes annotés, 0 write nu), mais le **print cosmétique
final** lève `UnicodeEncodeError` **après** écriture → exit non-nul → `check-artifacts` voit
« build a échoué » **ROUGE**. Vert aujourd'hui (runner UTF-8), **rouge en silence** le jour où
l'image runner change = classe « le runner n'est pas ton poste », mais **défaut, pas attestation**.
**Correctif — single-source à la frontière d'invocation, 0 fichier de production.** `PYTHONUTF8=1`
(PEP 540) impose stdout/stdin/défaut-fichier en UTF-8 **quelle que soit la locale**. Posé **une
fois** en `env:` **au niveau workflow** de `ci.yml` → s'applique à **tous les jobs** (21 builds +
25 suites + gates statiques). Miroir local : `run_ci.sh` `export PYTHONUTF8=1`. **Aucun des 20
modules touché** (anti-churn #5 — la fragilité est un contrat d'environnement d'invocation, pas 20
bugs à patcher un par un ; le fix vit là où le runner est configuré, comme le gate `cd`-ait déjà
dans le module pour fixer le contrat de CWD).
**Verrou — l'absence du fix est INVISIBLE sur runner UTF-8** (retirer l'`env:` reste vert
aujourd'hui) : classe de « vert trompeur » exactement traquée par ce dépôt. J'ancre donc le fix dans
le gate **existant** `check_ci_integrity.sh` (**INV-C**, pas de nouveau fichier gate #5) : il lit
l'`env:` top-level de `ci.yml` et exige `PYTHONUTF8: "1"`. **Teeth mutation-vérifié** : retrait de
la ligne `env:` → INV-C **mord** (exit 1) ; restauré → vert. INV-A/INV-B intacts (l'`env:` est
avant `jobs:` → hors du parseur de jobs).
**Preuve end-to-end.** `run_ci.sh` sous `env -u PYTHONUTF8 PYTHONCOERCECLOCALE=0 LC_ALL=C` (config
qui était **totalement ROUGE** avant) = **33 PASS · 0 FAIL** grâce au `export` miroir. Build-loop
sous `PYTHONUTF8=1 + LC_ALL=C` = **21 artefacts byte-identiques** (0 dérive, le fix ne change aucun
octet de sortie). `run_ci.sh` normal = **33 PASS**.
**Portée / anti-churn.** 4 fichiers : `ci.yml` (env), `run_ci.sh` (miroir), `check_ci_integrity.sh`
(INV-C verrou), `ci/README.md` (§2 détail INV-C + « Deux → Trois invariants »). **0 fichier de
production**, **0 artefact rebuild** (aucun `out/` touché → pas de rebuild `quality_report`, cf.
[[audit4big-rebuild-after-doc-edits]]), **0 chiffre inventé** (#6 — 20/21 dérivés de la boucle),
**0 commande VPS** (#8). run_ci = **33 PASS · 0 FAIL · 0 SKIP**. Mémoire neuve
*utf8-locale-runner-fix* (sœur de [[locale-tz-determinism-sweep]] dont elle **corrige l'angle mort**).
---
## Session 164319 · FIX régression RED : `quality_report.json` périmé après édition de doc → **VERT**
**Constat au démarrage.** `./run_ci.sh` = **32 PASS · 1 FAIL**`check-artifacts` RED sur
+16 -1
View File
@@ -181,7 +181,7 @@ puis commit.
### `check_ci_integrity.sh`
Prouve, en lisant `.gitea/workflows/ci.yml`, que le **câblage** du workflow tient —
car le job `gate` est le **seul verrou de merge** : un check absent de son `needs:`
ne bloque **rien**, même rouge. Deux invariants :
ne bloque **rien**, même rouge. Trois invariants :
- **INV-A**`gate.needs` == { tous les jobs définis } { `gate` } { jobs manuels }
(un job manuel = gardé par `if: … workflow_dispatch …`, ex. `e2e-baseline`,
légitimement hors du gate push/PR car il exige un serveur live). Détecte un job
@@ -193,6 +193,21 @@ ne bloque **rien**, même rouge. Deux invariants :
script (lib partagée `ci/lib.sh` — jamais un job propre). Un nouveau gate statique
**non câblé** (script mort) ou **décâblé**, ou une **lib morte** (sourcée par
personne), casse le check.
- **INV-C** — le workflow force le **mode UTF-8 de Python** (`env: PYTHONUTF8: "1"`
au niveau workflow → tous les jobs). Motif : chaque générateur clôt son `build`
par un `print("✅ …" / accents français)` vers stdout, dont l'encodage suit la
**locale du runner**. Sur une image runner ASCII (`LC_ALL=C` sans coercition
PEP 538, `PYTHONUTF8` non posé), ce print lève `UnicodeEncodeError` **après**
écriture des fichiers → `check-artifacts` voit un exit non-nul et les 25 suites
plantent : **tout le gate passe ROUGE le jour où l'image runner change**, alors
qu'il est VERT sur le poste dev (UTF-8) — classe « le runner n'est pas ton poste »
(sœur des sweeps hash-seed / locale-TZ / forward-compat, mais ici un **défaut
réel présent**, pas une simple attestation). `PYTHONUTF8=1` (PEP 540) impose
stdout/stdin/défaut-fichier en UTF-8 **partout** → 20 builds qui crashaient +
les suites redeviennent locale-robustes (prouvé : `run_ci.sh` sous
`LC_ALL=C` neutralisé = 33 PASS). Comme l'absence de cet `env:` est **invisible**
sur un runner UTF-8, INV-C l'**ancre** : le retirer casse ce gate au lieu de
dériver en silence. `run_ci.sh` **exporte la même variable** (miroir fidèle).
Ferme le trou laissé par les couvertures existantes (`audit_4big/registry`,
`qa/regression/discovery`) qui ne prouvent l'appartenance au gate que des jobs de
+22
View File
@@ -148,6 +148,28 @@ while IFS= read -r script; do
fi
done < <(git ls-files 'ci/*.sh' | grep -vx 'ci/check_ci_integrity.sh')
# --- INV-C : le workflow force le mode UTF-8 de Python (indépendance locale) --
# Chaque générateur clôt son `build` par un print(✅/accents) vers stdout ; sous
# une locale ASCII (runner minimal : LC_ALL=C, sans coercition PEP 538), ce print
# lève UnicodeEncodeError → `check-artifacts` ROUGE et les 25 suites plantent,
# EN SILENCE le jour où l'image runner change (VERT aujourd'hui car UTF-8). Le
# correctif est un `env: PYTHONUTF8: "1"` au niveau WORKFLOW (s'applique à tous
# les jobs). Comme son absence est invisible sur un runner UTF-8, on l'ancre ici :
# le retirer casse ce gate au lieu de dériver silencieusement. On lit l'`env:`
# top-level (indenté 2 espaces, AVANT `jobs:` → hors du parseur de jobs).
echo "== INV-C · le workflow force PYTHONUTF8 (I/O UTF-8 · indépendance locale runner) =="
utf8_mode="$(awk '
/^jobs:[[:space:]]*$/ { exit } # ne considérer que len-tête (avant jobs:)
/^env:[[:space:]]*$/ { inenv=1; next }
inenv && /^[^[:space:]]/ { inenv=0 } # fin du bloc env: (clé non indentée)
inenv && match($0, /^[[:space:]]+PYTHONUTF8:[[:space:]]*["'\'']?1["'\'']?[[:space:]]*$/) { print "1" }
' "$CI")"
if [[ "$utf8_mode" == "1" ]]; then
ok "workflow env: PYTHONUTF8=\"1\" → stdout/défaut-fichier UTF-8 sur tout runner (builds + suites locale-robustes)"
else
report "workflow SANS \`env: PYTHONUTF8: \"1\"\` top-level → gate locale-fragile (RED silencieux sur runner ASCII · cf. print ✅ en fin de build)"
fi
echo
if [[ "$FAIL" -eq 0 ]]; then
echo -e "\033[32m✅ Câblage CI intègre (gate agrège tout job non-manuel · gates statiques verrouillés).\033[0m"
+7
View File
@@ -73,6 +73,13 @@ cd "$ROOT" || exit 3
CI_YML=".gitea/workflows/ci.yml"
[ -f "$CI_YML" ] || { echo "run_ci.sh : $CI_YML introuvable." >&2; exit 3; }
# Miroir de l'`env:` workflow de ci.yml — force le mode UTF-8 de Python pour
# tous les jobs rejoués ici, de sorte que ce miroir local reproduise fidèlement
# le gate même si le poste tourne sous une locale ASCII (LC_ALL=C). Sans cela,
# les générateurs (print ✅/accents en fin de `build`) et les suites planteraient
# ici alors qu'ils passent en CI (cf. ci.yml env PYTHONUTF8 · check_ci_integrity INV-C).
export PYTHONUTF8=1
MODE="all"
case "${1:-}" in
--static) MODE="static" ;;