Compare commits

...

12 Commits

Author SHA1 Message Date
Claude Code DTP Worker 9c062ef83d REFERENCE · OTO Design System v1 · palette/typo/composants/writing/i18n/voice/mobile/PDF
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 / 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 / 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 / E2E baseline Playwright (manuel) (push) Has been cancelled
Mobile Build (EAS) / Préflight config EAS + état secrets (push) Has been cancelled
CI / Gate qualité (agrégat) (push) Has been cancelled
Mobile Build (EAS) / EAS build iOS (App Store (push) Has been cancelled
Mobile Build (EAS) / EAS build Android (Play Store) (push) Has been cancelled
2026-08-03 08:36:31 +00:00
Claude Code DTP Worker 33fe561f51 [DTP-Worker 20260803_080712] Sprint 8 QA · passe de vérification d'intégrité exhaustive — 0 dérive (roadmap 15/15 · CI 30 PASS · docstring-vs-code CLEAN · README 22/22/569 gaté · 22-vs-23 réconcilié)
Session de non-régression pure (livrable Sprint 8). Aucune tâche roadmap
incomplète : acceptance_matrix = 15/15 in_repo, verdict true. Vérifié CLEAN sur
4 dimensions : roadmap, CI (30 PASS), dérive docstring-vs-code (sweep Explore),
chiffres data-derived README (re-dérivés des artefacts 4big/regression, gate
check-readme-claims PASS). Signal 22-vs-23 suites écarté : 23e job CI = self-module
qa/regression exclu de sa matrice par SoD (déjà doc ci/README.md:226), pas une dérive.
Gate-neutre : seule l'entrée Canal 1 est écrite, aucun code/artefact/gate touché.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 08:12:47 +00:00
Claude Code DTP Worker 1f5a1622e3 [DTP-Worker 20260803_073711] Sprint 5/8 · doc · Canal 2 daily_reports remis à jour (session 070711 manquante)
Le snapshot stakeholder daily_reports/2026-08-03.md s'arrêtait à l'addendum
060704 ; la dernière session commitée (070711 · dbde8fa · 3 surfaces jumelles
regression_run.json) n'y figurait pas. Addendum ajouté avant la table launch-
readiness, fidèle au commit. Chiffres re-vérifiés contre artefacts commités :
PASS · 22 modules · 22 suites · 569/569 · inchangés. daily_reports non gaté →
gate-neutre. Chasse doc-vs-code préalable (Explore, 12 modules) = CLEAN.
run_ci.sh 30 PASS 0 FAIL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 07:43:09 +00:00
Claude Code DTP Worker dbde8fac46 [DTP-Worker 20260803_070711] Sprint 8 QA · fix · 3 surfaces jumelles résiduelles du mensonge regression_run.json « non déterministe/non commité »
Le fix 89eb8e6 (session 053701) avait corrigé regression_gen.py docstring +
README, mais la même contre-vérité subsistait dans 3 surfaces manquées :
 · reglib/builder.py:10-13 (docstring module — pointait vers .gitignore comme
   autorité alors que le .gitignore affirme l'INVERSE)
 · reglib/builder.py:71 (docstring run_matrix)
 · regression_gen.py:82-85 (champ hors_perimetre_worker → coule dans MANIFEST.json
   commité/gaté ; contredisait le docstring corrigé 12 lignes plus haut)

Ground-truth (4 sources) : git ls-files (commité) · .gitignore (commité+byte-
déterministe) · ci/check_regression.sh (exige byte-identité d'un run frais) ·
docstring regression_gen.py:26 déjà réaligné. MANIFEST.json régénéré (build),
plan + regression_run.json inchangés. Consommateur aval : aucun. run_ci.sh 30
PASS 0 FAIL. Classe prose-facts-vs-numeric-drift / docstring-vs-code, gate-neutre.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 07:15:25 +00:00
Claude Code DTP Worker db817309a0 [DTP-Worker 20260803_063711] Sprint 5/8 · doc · Canal 2 daily_reports remis à jour (3 sessions manquantes depuis 040643)
Le snapshot stakeholder du jour s'arrêtait à l'addendum 040643 → 3 sessions net
postérieures ajoutées (050654 ci/README 2e workflow · 053701 fix regression_run.json
prose-fact · 060704 fix citation roadmap bancable), toutes correctifs d'intégrité
n'affectant pas les chiffres launch-readiness. Chiffres re-dérivés d'artefacts
(22/22 · 569/569 · 15/15 · README Mobile 4931 o) → table de clôture inchangée.
Sweep préalable (agent Explore) globs README/docstrings/comptes/liens = 0 dérive
ungated. Gate-neutre (daily_reports non gaté) · run_ci.sh 30 PASS 0 FAIL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 06:43:37 +00:00
Claude Code DTP Worker 88d9955f90 [DTP-Worker 20260803_060704] Sprint 3 · fix · Citation roadmap fantôme dans bancable (prose-facts-vs-numeric-drift)
Docstring bancable_gen.py:5 + bancable/README.md:5 attribuaient au fichier
ROADMAP_8_WEEKS_OR_LESS.md un libellé verbatim « 40_llm_outputs/ + rapports
bancables FR/EN/ES » ABSENT de la roadmap (grep = 0 occurrence). Le §Sprint 3
réel dit « Faisabilité Auto » → « génération 4 volets <1h ». Le libellé cité
vient des daily_reports (planif S3 du 2026-07-30), pas de la roadmap : citation
mal-attribuée (même classe que « regression_run.json non commité »).

Fix : §Sprint 3 cité fidèlement + volet financier bancable ré-attribué aux
daily_reports / Portail Bancables 4Big, avec mention « pas un texte roadmap ».
Consommateur qa/audit_4big/quality_report.json régénéré (README bancable
6103 → 6439 octets · verdict PASS 22/22 = 100/100 inchangé). Libellé fantôme
cité par aucun gate. run_ci.sh 30 PASS 0 FAIL. Zéro module, zéro gate (#5).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 06:16:35 +00:00
Claude Code DTP Worker 3d8ccb0249 [DTP-Worker 20260803_053701] log · session fix dérive regression_run.json doc-vs-réalité 2026-08-03 05:43:26 +00:00
Claude Code DTP Worker 89eb8e68ad [DTP-Worker 20260803_053701] Sprint 8 · fix · Dérive doc-vs-réalité regression_run.json (classe prose-facts, jumelle du fix root-README)
`regression_gen.py` (docstring l.26) ET `qa/regression/README.md` (§ hand-off VPS
l.76) décrivaient encore la sortie `run` comme « NON déterministe → non commitée »
/ « manuel · non gated push/PR ». Faux sur les trois points, contredit par son
propre gate dédié `ci/check_regression.sh` (step `check-regression` de ci.yml) :
`regression_run.json` EST commité (git ls-files), EST déterministe (aucun
horodatage/hôte → deux `run` byte-identiques, en-tête du gate l.24-25) et EST
byte-gaté à chaque push/PR. Même dérive « regression_run.json non commité » déjà
corrigée dans le README racine (76fb0e7) mais restée dans le module lui-même.

Réalignés sur la réalité + citation du gate. Consommateur `qa/audit_4big/out/
quality_report.json` régénéré (évidence DOC 4236→4396 octets · verdict PASS 22/22
≥95 min 100 inchangé · 1 insertion/1 suppression · artifact-reproducibility-gate).
Docstring .py non byte-gatée (aucun gate n'en lit les octets). run_ci.sh 30 PASS 0 FAIL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 05:43:06 +00:00
Claude Code DTP Worker 1af5d01ccf [DTP-Worker 20260803_050654] Sprint 1 DevOps · doc · ci/README complété : le dépôt a DEUX workflows Gitea Actions (ci.yml + mobile-build.yml depuis af84b21) mais le livrable CI/CD n'ouvrait que sur ci.yml → second workflow jamais mentionné (référence à sens unique : mobile-build.yml pointe vers ci/README, pas l'inverse). Nouvelle sous-section §1 « mobile-build.yml (HORS gate) » : vérifié par construction hors gate.needs (check-ci-integrity ne verrouille que ci.yml), même runner, SKIP-safe sans EAS_TOKEN. Prose éditoriale sans chiffre data-derived → gate-neutre. Sweep préalable 20 générateurs docstring-vs-CODE = CLEAN, ancres roadmap + chiffres daily report re-vérifiés. run_ci.sh 30 PASS 0 FAIL
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 05:13:38 +00:00
Claude Code DTP Worker b631774160 [DTP-Worker 20260803_043644] Sprint 5/8 · doc · Canal 2 daily_reports remis à jour : snapshot stakeholder du jour s'arrêtait à l'addendum 030641 (fiche store) → 2 livrables manquants ajoutés (P1 workflow CI/CD mobile-build.yml 033642 + fix doc-vs-CODE Mobile 040643) + table launch-readiness fin de journée. Chiffres re-dérivés d'artefacts (569/569 · 22/22 · 15/15). Gate-neutre (daily_reports non gaté) · run_ci.sh 30 PASS 0 FAIL
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 04:41:18 +00:00
Claude Code DTP Worker 953e683be3 [DTP-Worker 20260803_040643] Sprint 5 · fix · Dérive doc-vs-CODE Mobile : cmd_build écrit 5 fichiers (store_listing.json inclus) mais docstring app_config_gen.py « les 4 fichiers » + glob README omettaient store_listing → réalignés sur 5. Consommateur qa/audit_4big/quality_report.json régénéré (évidence DOC byte-count · verdict PASS 22/22 inchangé) · run_ci.sh 30 PASS 0 FAIL 2026-08-03 04:12:15 +00:00
Claude Code DTP Worker af84b21f89 [DTP-Worker 20260803_033642] Sprint 5 P1 · feat · CI/CD Mobile : workflow Gitea Actions mobile-build.yml (build EAS iOS App Store #32 + Android Play Store)
Livrable FONCTIONNEL non fait, explicitement demandé par DIRECTIVE_MOBILE_STORES
_20260803.md P1 (« Créer .gitea/workflows/mobile-build.yml ») — classé non-bloqueur
in-périmètre worker. Triggers push main + tags v* + workflow_dispatch ; jobs
preflight (toujours vert) + build-ios + build-android → eas build --profile
production --non-interactive (profils lus de mobile/app_config/out/eas_build.json).

Activation différée (#6/#8) : builds gardés par `if secrets.EAS_TOKEN != '' &&
vars.MOBILE_NATIVE_REPO != ''` → SKIP tant que Michel n'a pas fourni token+repo
natif → CI jamais rouge avant activation ; aucun credential fabriqué (a_confirmer).
Code Expo natif = autre dépôt Gitea, cloné au run (jamais recopié). Gitea only (#2).

Consommateur régénéré : pointeur README mobile (4261→4917 o) mesuré par critère DOC
de l'audit 4Big → audit_4big_gen.py build régénéré (verdict inchangé 22/22 ≥95).
check_ci_integrity n'inspecte que ci.yml → 2e workflow invisible au gate.
Zéro nouveau module · zéro gate ajouté (#5). run_ci.sh 30 PASS · 0 FAIL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 03:46:18 +00:00
14 changed files with 981 additions and 18 deletions
+135
View File
@@ -0,0 +1,135 @@
# ============================================================================
# Mobile Build (EAS) · OTO Enterprise OS DTP · Gitea Actions
# ----------------------------------------------------------------------------
# Roadmap Sprint 5 l.56-57 « Mobile : Rebuild Expo 54 + submit App Store #32 +
# Play Store » · DIRECTIVE_MOBILE_STORES_20260803.md · P1 « CI/CD Mobile ».
#
# Plateforme : Gitea Actions UNIQUEMENT (CLAUDE.md #2 · JAMAIS GitHub).
# Runner : act_runner enregistré sur le VPS avec le label « ubuntu-latest »
# (même runner que ci.yml · voir ci/README.md).
#
# PÉRIMÈTRE (#8). Ce worker versionne la CONFIG CI/CD ; l'exécution `eas build` /
# `eas submit` a lieu HORS repo (service EAS / stores), pilotée par l'agent
# Mobile. La config des profils de build est la source de vérité versionnée
# 05_deliverables_mvp/mobile/app_config/out/eas_build.json (profils development /
# preview / production) — ce workflow ne fait que l'invoquer.
#
# CODE APP HORS REPO. Le code natif Expo vit dans un AUTRE dépôt Gitea
# (/opt/oto/mobile/native/ · Expo SDK 51 actuel → cible Expo 54, roadmap l.56).
# Il est cloné au run depuis ${{ vars.MOBILE_NATIVE_REPO }} — jamais recopié ici.
#
# ACTIVATION DIFFÉRÉE (#6 · zéro credential inventé). Tant que le secret
# EAS_TOKEN n'est pas fourni par Michel (expo.dev · 2 min · cf. directive
# « Vrais bloqueurs »), les jobs de build sont SKIP — donc ce workflow ne rend
# JAMAIS le CI rouge avant que Michel n'active. Le job `preflight` reste vert et
# rapporte l'état des secrets à fournir. Rien n'est fabriqué : tout identifiant
# (repo natif, token, credentials Apple/Google) est un secret/variable
# `a_confirmer`, cohérent avec les champs `null · a_confirmer` du livrable mobile.
# ============================================================================
name: Mobile Build (EAS)
on:
# Conforme directive P1 : « Trigger sur push branche main ou tag v* ».
push:
branches: [main]
tags: ['v*']
paths:
- '05_deliverables_mvp/mobile/**'
- '.gitea/workflows/mobile-build.yml'
workflow_dispatch:
inputs:
platform:
description: 'Plateforme à builder'
required: true
default: 'all'
type: choice
options: [all, ios, android]
profile:
description: 'Profil EAS (cf. eas_build.json)'
required: true
default: 'production'
type: choice
options: [production, preview, development]
# Un seul build mobile à la fois par ref (annule le précédent en cours).
concurrency:
group: mobile-build-${{ github.ref }}
cancel-in-progress: true
env:
# Profil par défaut (aligné directive P4 : builds `--profile production`).
EAS_PROFILE: ${{ github.event.inputs.profile || 'production' }}
# Config des profils versionnée par le worker (source de vérité).
EAS_CONFIG: 05_deliverables_mvp/mobile/app_config/out/eas_build.json
jobs:
# --------------------------------------------------------------------------
# Préflight : TOUJOURS vert. Prouve que la config EAS versionnée est présente
# et rapporte l'état des secrets requis, SANS jamais échouer avant activation.
# --------------------------------------------------------------------------
preflight:
name: Préflight config EAS + état secrets
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Config EAS versionnée présente (eas_build.json)
run: test -f "$EAS_CONFIG" && echo "OK · profils build/submit versionnés dans $EAS_CONFIG"
- name: État des secrets requis (aucun secret n'est loggé)
run: |
echo "Profil sélectionné : $EAS_PROFILE"
if [ -n "${{ secrets.EAS_TOKEN }}" ]; then
echo "EAS_TOKEN : présent → les jobs de build vont s'exécuter."
else
echo "EAS_TOKEN : ABSENT → jobs de build SKIP (attente Michel · expo.dev)."
fi
[ -n "${{ vars.MOBILE_NATIVE_REPO }}" ] && echo "MOBILE_NATIVE_REPO: configuré." || echo "MOBILE_NATIVE_REPO: a_confirmer (dépôt Gitea du code natif Expo)."
# --------------------------------------------------------------------------
# Build iOS · SKIP tant que EAS_TOKEN absent (activation Michel · #6/#8).
# App Store #32 · `eas build --platform ios --profile production`.
# --------------------------------------------------------------------------
build-ios:
name: EAS build iOS (App Store #32)
runs-on: ubuntu-latest
needs: preflight
if: ${{ secrets.EAS_TOKEN != '' && vars.MOBILE_NATIVE_REPO != '' && (github.event.inputs.platform == 'all' || github.event.inputs.platform == 'ios' || github.event_name != 'workflow_dispatch') }}
env:
EXPO_TOKEN: ${{ secrets.EAS_TOKEN }}
steps:
- name: Cloner le code natif Expo (dépôt Gitea séparé)
uses: actions/checkout@v4
with:
repository: ${{ vars.MOBILE_NATIVE_REPO }}
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Installer EAS CLI
run: npm install -g eas-cli
- name: EAS build iOS (production · non-interactive)
run: eas build --platform ios --profile "$EAS_PROFILE" --non-interactive --no-wait
# --------------------------------------------------------------------------
# Build Android · SKIP tant que EAS_TOKEN absent (activation Michel · #6/#8).
# Play Store · `eas build --platform android --profile production`.
# --------------------------------------------------------------------------
build-android:
name: EAS build Android (Play Store)
runs-on: ubuntu-latest
needs: preflight
if: ${{ secrets.EAS_TOKEN != '' && vars.MOBILE_NATIVE_REPO != '' && (github.event.inputs.platform == 'all' || github.event.inputs.platform == 'android' || github.event_name != 'workflow_dispatch') }}
env:
EXPO_TOKEN: ${{ secrets.EAS_TOKEN }}
steps:
- name: Cloner le code natif Expo (dépôt Gitea séparé)
uses: actions/checkout@v4
with:
repository: ${{ vars.MOBILE_NATIVE_REPO }}
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Installer EAS CLI
run: npm install -g eas-cli
- name: EAS build Android (production · non-interactive)
run: eas build --platform android --profile "$EAS_PROFILE" --non-interactive --no-wait
+395
View File
@@ -1,5 +1,92 @@
# Activity Log · 2026-08-03 · Claude Code DTP Worker # Activity Log · 2026-08-03 · Claude Code DTP Worker
## Session 063711 · Sprint 5/8 · Canal 2 `daily_reports/` remis à jour (3 sessions manquantes depuis 040643)
**Contexte + choix de tâche.** `./run_ci.sh` au démarrage : **30 PASS · 0 FAIL · 0 SKIP**,
arbre propre. Roadmap 1→8 intégralement livrée + gatée verte. Un sweep de dérive dédié
(agent Explore : globs de sortie README-vs-`os.path.join`, docstrings générateurs, comptes
prose, liens Markdown) a rendu **0 dérive ungated** — les gates existants
(`check_readme_claims`/`check_artifacts`/`check_regression`/`check_docs`) couvrent l'acquis,
et re-scanner serait redondant (#5). La valeur restante réelle in-périmètre : la **currency
du canal 2 stakeholder** (contrat « Rapports quotidiens »), classe [[two-logging-channels]].
**Défaut trouvé (dérive de couverture, réelle).** Le snapshot `daily_reports/2026-08-03.md`
s'arrêtait à l'addendum session `040643`. **Trois** sessions net postérieures manquaient au
snapshot — toutes des correctifs d'intégrité doc (aucun ne bouge les chiffres
launch-readiness, d'où table de clôture inchangée) :
- `050654``ci/README.md` complété (2e workflow `mobile-build.yml`, commit `1af5d01`) ;
- `053701` — fix prose-fact `regression_run.json` doc-vs-réalité (commits `89eb8e6` + `3d8ccb0`) ;
- `060704` — fix citation roadmap fantôme module bancable (commit `88d9955`).
**Réalisé.** Trois addenda concis insérés **avant** la table « fin de journée » (qui reste
la synthèse de clôture), 100 % sourcés : chaque addendum cite son/ses commit(s), sa classe
de dérive et le consommateur régénéré le cas échéant. Aucune valeur inventée.
**Chiffres re-dérivés d'artefacts (aucun saisi à la main).** `regression_run.json.totals`
= 22 suites · **569 ran / 569 passed · 0/0/0** ; `quality_report.json` verdict **PASS · 22
modules · min 100** (seuil 95) ; `acceptance_matrix.json` **15/15 `status=in_repo`**
(`all_modules_gated` + `all_artifacts_exist` all true) ; README Mobile **4931 octets**
(`wc -c`). Tous concordants → table de clôture laissée **inchangée** (correcte telle quelle).
**Sûreté du changement.** `daily_reports/` n'est ni un artefact `out/` byte-gaté ni une
source de claims de `check_readme_claims` (surfaces gatées = README/AGENT.md, pas les
rapports quotidiens) → édition **gate-neutre**. Aucun claim numérique gaté touché · aucun
terme interdit · aucune logique de prod ni de gate modifiée.
**Vérifications.** `./run_ci.sh`**30 PASS · 0 FAIL · 0 SKIP** (inchangé) · `git status`
= 1 fichier. **Zéro nouveau module · zéro gate ajouté (#5).** Aucune commande touchant au
VPS (#8) · aucun `git clean` <!-- ci-allow : mention de l'interdit absolu, jamais exécuté -->.
## Session 033642 · Sprint 5 P1 · Livrable FONCTIONNEL : workflow CI/CD Mobile `.gitea/workflows/mobile-build.yml` (build EAS iOS + Android)
**Contexte + choix de tâche.** `./run_ci.sh` au démarrage : **30 PASS · 0 FAIL · 0 SKIP**,
arbre propre. Michel : « commits fonctionnels, pas juste docs ». La roadmap est couverte
par des modules gatés+verts, mais `DIRECTIVE_MOBILE_STORES_20260803.md` (Sprint 5, actif)
liste explicitement en **P1 · CI/CD Mobile** la création de `.gitea/workflows/mobile-build.yml`
— classée **non-bloqueur** (« configurer sans token, activation quand Michel fournit »),
donc **in-périmètre worker** (fichier config versionné, aucune exécution VPS/stores #8).
Vérifié absent : `.gitea/workflows/` ne contenait que `ci.yml`. **Vraie tâche fonctionnelle
non faite** → exécutée.
**Livrable créé : `.gitea/workflows/mobile-build.yml`.**
- **Triggers** (conformes directive P1) : push `main` + tags `v*` (paths `mobile/**` +
le workflow) + `workflow_dispatch` (inputs `platform` all/ios/android, `profile`).
- **Jobs** : `preflight` (TOUJOURS vert · prouve la présence de la config EAS versionnée
`mobile/app_config/out/eas_build.json` + rapporte l'état des secrets, sans jamais les
logger) ; `build-ios` (App Store #32) + `build-android` (Play Store) → `eas build
--platform … --profile production --non-interactive` (directive P4).
- **Source de vérité** : les profils de build viennent de l'artefact versionné
`eas_build.json` (development/preview/production) — pas réinventés.
- **Code natif hors repo** : le code Expo vit dans un **autre dépôt Gitea**
(`/opt/oto/mobile/native/` · Expo 51→cible 54) ; cloné au run depuis la variable
`vars.MOBILE_NATIVE_REPO`**jamais recopié ici**.
**Sûreté (activation différée · #6 zéro invention · #8).** Les jobs de build sont gardés
par `if: secrets.EAS_TOKEN != '' && vars.MOBILE_NATIVE_REPO != ''`**SKIP** tant que
Michel n'a pas fourni token+repo (« Vrais bloqueurs » de la directive : EAS_TOKEN 2 min sur
expo.dev). Conséquence : ce workflow **ne rend JAMAIS le CI rouge** avant activation, et
`preflight` reste vert et informatif. Aucun credential fabriqué : token, repo natif,
appleId/ascAppId/serviceAccount restent des secrets/vars `a_confirmer` — cohérent avec les
champs `null · a_confirmer` du livrable mobile. Plateforme **Gitea Actions uniquement** (#2).
**Non-régression des gates (vérifié).** `check_ci_integrity.sh` n'inspecte QUE `ci.yml`
(chemin en dur `CI=".gitea/workflows/ci.yml"`) → le 2e workflow lui est invisible, aucun
job à ajouter à `gate.needs`. `guard_constraints.sh` vert (aucune URL/usage interdit ;
`actions/checkout@v4` déjà toléré via `ci.yml`). YAML valide (pyyaml).
**Consommateur régénéré (classe [[artifact-reproducibility-gate]]).** Ajout d'un pointeur
concis (paragraphe « CI/CD Mobile » + 1 ligne au tableau périmètre) dans
`mobile/app_config/README.md` → sa taille passe 4261→4917 octets, mesurée par le critère
**DOC** de l'audit 4Big. `check-artifacts` a viré ROUGE (dérive attendue) →
`audit_4big_gen.py build -o out` régénéré : **seule** la ligne `evidence "README.md (…octets)"`
change ; verdict inchangé **PASS · 22/22 modules ≥ 95**. Lien Markdown vérifié résolvant
(`../../../.gitea/workflows/mobile-build.yml`).
**Vérifications finales.** `./run_ci.sh`**30 PASS · 0 FAIL · 0 SKIP**. **Zéro nouveau
module · zéro gate ajouté (#5)** · aucune commande VPS (#8).
Aucun `git clean` exécuté <!-- ci-allow : mention de l'interdit absolu, jamais exécuté -->.
## Session 020634 · Dérive ground-truth résiduelle : roadmap L18 (colonne « Existe déjà ») affirmait encore « Expo 54 » — corrigée → Expo 51 réel (#6) ## Session 020634 · Dérive ground-truth résiduelle : roadmap L18 (colonne « Existe déjà ») affirmait encore « Expo 54 » — corrigée → Expo 51 réel (#6)
**Contexte.** `./run_ci.sh` au démarrage : **30 PASS · 0 FAIL · 0 SKIP**, arbre propre. **Contexte.** `./run_ci.sh` au démarrage : **30 PASS · 0 FAIL · 0 SKIP**, arbre propre.
@@ -301,3 +388,311 @@ contextes **cible/futur** (`eas build (Expo 54)`, items acceptance `out_of_scope
**Vérifications.** `./run_ci.sh` → **30 PASS · 0 FAIL · 0 SKIP** (inchangé). **Zéro **Vérifications.** `./run_ci.sh` → **30 PASS · 0 FAIL · 0 SKIP** (inchangé). **Zéro
nouveau module · zéro gate ajouté (#5) · aucune logique de prod ni de gate touchée.** nouveau module · zéro gate ajouté (#5) · aucune logique de prod ni de gate touchée.**
Aucune commande touchant au VPS (#8) · aucun `git clean` <!-- ci-allow : mention de l'interdit absolu, jamais exécuté -->. Aucune commande touchant au VPS (#8) · aucun `git clean` <!-- ci-allow : mention de l'interdit absolu, jamais exécuté -->.
## Session 040643 · Dérive doc-vs-CODE Mobile · `app_config_gen.py` + README (« 4 fichiers » → 5, `store_listing.json` omis)
**Contexte.** `./run_ci.sh` au démarrage : **30 PASS · 0 FAIL · 0 SKIP**, arbre propre.
Roadmap intégralement couverte par des modules gatés+verts ; priorité recherchée :
tâche **fonctionnelle** in-repo (Michel · « commits fonctionnels »), périmètre worker
(repo seul · pas de VPS #8 · pas de nouveau module #5). Le dernier livrable touché
(commit `af84b21`, workflow `mobile-build.yml`) a orienté l'audit vers le module Mobile
`05_deliverables_mvp/mobile/app_config`.
**Défaut trouvé (réel · classe [[docstring-vs-code-drift]], ungated).** Le générateur
`cmd_build` écrit **5** fichiers JSON (`app_config`, `eas_build`, `role_navigation`,
`store_listing`, `MANIFEST` — vérifié `app_config_gen.py:239-243`), mais **deux**
surfaces de doc décrivaient encore **4** — l'output `store_listing.json` (ajouté après
coup) y était omis :
- **`app_config_gen.py` l.20** (docstring, bloc « Sous-commandes ») : `build … -> écrit
les 4 fichiers ci-dessus` — alors que l'énumération **juste au-dessus** (l.11-17) liste
bien **5** fichiers, dont `store_listing.json` : incohérence **interne** au docstring,
off-by-one classique laissé par l'insertion tardive de la fiche store ;
- **`README.md` § Utilisation** : `# écrit out/{app_config,eas_build,role_navigation}.json
+ MANIFEST.json` — `store_listing.json` **absent** du glob, alors que la § « Sorties »
du même README le documente déjà comme sortie produite.
**Correctif (2 éditions chirurgicales, gate-neutres).**
- l.20 → `écrit les 5 fichiers ci-dessus` (aligné sur l'énumération l.11-17) ;
- README → `out/{app_config,eas_build,role_navigation,store_listing}.json + MANIFEST.json`.
- Sweep résiduel `grep « 4 fichiers » / « les 4 » / « role_navigation}.json » / « 3
fichiers »` sur `05_deliverables_mvp/mobile/` + `03_agents/mobile/` → **0** autre
occurrence stale. La § « Sorties » (5 items) et « Résultat courant » du README étaient
déjà correctes.
**Régénération du consommateur (obligatoire · [[artifact-reproducibility-gate]]).**
L'édition du README a fait dériver `qa/audit_4big/out/quality_report.json` (critère DOC :
évidence `README.md (4917 → 4931 octets)`). `python3 audit_4big_gen.py build` → verdict
**PASS · 22/22 modules ≥ 95 (min 100)** inchangé ; seul le byte-count évolue. `git diff`
du report = **1 insertion / 1 suppression** (l'octet-compte du README Mobile).
**Sûreté du changement.** Aucun claim numérique gaté touché (le « 5 » du docstring n'est
pas re-dérivé par un gate de compte ; le glob README n'est pas un lien Markdown → hors
`check_docs`) ; aucun terme interdit ; aucune logique de prod ni de gate modifiée.
**Vérifications.** `./run_ci.sh` → **30 PASS · 0 FAIL · 0 SKIP**. **Zéro nouveau module ·
zéro gate ajouté (#5)** — pure correction de vérité-terrain doc-vs-CODE. Aucune commande
touchant au VPS (#8) · aucun `git clean` <!-- ci-allow : mention de l'interdit absolu, jamais exécuté -->.
## Session 043644 · Sprint 5/8 · Canal 2 `daily_reports/` remis à jour (2 livrables du jour manquants)
**Contexte.** `./run_ci.sh` au démarrage : **30 PASS · 0 FAIL · 0 SKIP**, arbre propre.
Roadmap 1→8 intégralement livrée côté repo + gatée verte (22/22 qualité · 569/569
régression · 15/15 recette). Pas de module à créer (#5 interdit l'invention). Périmètre
worker (repo seul · pas de VPS #8). Audit du canal stakeholder
`daily_reports/2026-08-03.md`.
**Constat (dérive de couverture, réelle).** Le canal 2 (instantané stakeholder du jour ·
contrat roadmap « Rapports quotidiens ») s'arrêtait à l'addendum session `030641` (fiche
store). Les **deux livrables du jour les plus significatifs manquaient** au snapshot :
- session `033642` — **Sprint 5 P1 · workflow CI/CD Mobile `mobile-build.yml`** (commit
`af84b21`) : un vrai livrable fonctionnel de la roadmap, absent du snapshot ;
- session `040643` — fix dérive doc-vs-CODE Mobile (`cmd_build` 5 fichiers · commit
`953e683`).
Classe [[two-logging-channels]] : le canal daily_reports (snapshot roadmap) doit rester
courant, distinct de l'activity_log per-session.
**Réalisé.** Deux addenda ajoutés à `daily_reports/2026-08-03.md`, 100 % sourcés :
- addendum `033642` : workflow `mobile-build.yml` (3 jobs `preflight`/`build-ios`/
`build-android` · gardes `if secrets.EAS_TOKEN != '' && vars.MOBILE_NATIVE_REPO != ''`
→ SKIP-safe, CI jamais rouge avant activation Michel · profils EAS de `eas_build.json`
source de vérité · Gitea-only #2) ;
- addendum `040643` : réalignement docstring/README 4→5 fichiers + consommateur
`quality_report.json` régénéré (README Mobile 4917→4931 o · verdict PASS 22/22 inchangé) ;
- table « État launch-readiness · fin de journée » (chiffres re-vérifiés d'artefacts).
**Chiffres re-dérivés (aucun saisi à la main).** `regression_run.json.totals` = 22 suites ·
**569 ran · 569 passed · 0/0/0** · `quality_report.json` verdict **PASS · 22 modules** ·
`acceptance_matrix.json` **15/15 in_repo** · README Mobile **4931 octets** (`wc -c`) ·
workflow **3 jobs** (`grep`). Tous concordants.
**Sûreté du changement.** `daily_reports/` n'est ni un artefact `out/` byte-gaté ni un
doc d'entrée de `check_readme_claims` (surfaces gatées = README/AGENT.md, pas les
rapports quotidiens) → édition **gate-neutre**. Aucun claim numérique gaté touché ·
aucun terme interdit · aucune logique de prod ni de gate modifiée · zéro nouveau module ·
zéro gate ajouté (#5).
**Vérifications.** `./run_ci.sh` → **30 PASS · 0 FAIL · 0 SKIP**. Aucune commande touchant
au VPS (#8) · aucun `git clean` <!-- ci-allow : mention de l'interdit absolu, jamais exécuté -->.
---
## Session `20260803_050654` · doc DevOps — `ci/README.md` complété : second workflow `mobile-build.yml`
**Sweep de vérité d'abord (aucune dérive trouvée sur les axes usuels).** Balayage
docstring-vs-CODE / README-vs-CODE des **20** générateurs (`*_gen.py` + `lib/generator.py`)
→ **CLEAN** (chaque docstring/README concorde avec les fichiers réellement écrits ;
la dérive `4→5 cmd_build` de la veille était le dernier cas). Ancres roadmap de
`acceptance_matrix.json` (33/39/46/52/58/64/70/76 + 81-87) re-vérifiées contre le fichier
roadmap → exactes. Câblage `gate.needs` (30 entrées) == miroir `run_ci.sh` → concordant.
Chiffres du daily report re-dérivés d'artefacts : `regression_run.json.totals` **569/569 ·
0/0/0**, `quality_report.json` **PASS · 22 modules**, `acceptance_matrix.json` **15/15
in_repo** → tous exacts.
**Gap réel corrigé (complétude doc, classe `prose-facts-vs-numeric-drift`).** Depuis
l'ajout de `.gitea/workflows/mobile-build.yml` (commit `af84b21`), le dépôt possède
**deux** workflows Gitea Actions, mais le livrable CI/CD `ci/README.md` § 1 s'ouvrait sur
« Workflow : `ci.yml` » et ne mentionnait **jamais** le second — alors que `mobile-build.yml`
lui, pointe vers `ci/README.md` (« même runner · voir ci/README.md »). Référence à sens
unique → doc CI/CD incomplète pour un auditeur du dépôt.
**Correctif.** Nouvelle sous-section § 1 « Second workflow Gitea Actions — `mobile-build.yml`
(HORS gate de merge) » : explicite, **vérifié par construction**, que ce workflow
n'appartient pas au gate (`check-ci-integrity` ne verrouille que `ci.yml` via sa variable
`CI=` ; aucun job dans `gate.needs` ; `run_ci.sh` ne le rejoue pas), qu'il tourne sur le
**même runner**, et qu'il est **SKIP-safe** (jobs de build en SKIP tant que `EAS_TOKEN`
absent → CI jamais rouge). Liens relatifs ajoutés vers le workflow et le README du module
Mobile (résolus par `check_docs` relativement à `ci/`).
**Sûreté du changement.** Prose éditoriale **sans chiffre data-derived** (aucun compte de
jobs, aucune valeur gatée) → `check_readme_claims` neutre. Aucun terme interdit (#2 Gitea
only respecté) · aucun `out/*.json` touché → `check_artifacts` neutre · aucun nouveau
`ci/*.sh` ni assertion → `check_ci_integrity`/#5 neutres. Table § 1 inchangée (lignes
one-liner préservées ; détail placé en sous-section, cf. discipline `ci-readme` du dépôt).
**Vérifications.** `./run_ci.sh` → **30 PASS · 0 FAIL · 0 SKIP** (dont `check-docs` liens
OK · `check-readme-claims` vert). Aucune commande VPS (#8) · aucun `git clean` <!-- ci-allow : mention de l'interdit, jamais exécuté -->.
## Session `20260803_053701` · fix · Dérive doc-vs-réalité `regression_run.json` (classe `prose-facts-vs-numeric-drift`, jumelle du fix root-README)
**Contexte.** Repo tout-vert au démarrage (`run_ci.sh` 30 PASS / 0 FAIL). Sweep
mécanique docstring-vs-CODE sur les ~30 générateurs (comparaison des `.json`
listés dans chaque docstring vs les littéraux écrits par `os.path.join(out, …)`) :
tous les « DOCSTRING-not-written » se sont révélés être des fichiers d'ENTRÉE
(`rbac_50_roles.json`, `BRIEF.json`, `eas.json`…) → faux positifs. **Un seul**
écart réel : `regression_gen.py` écrit `regression_run.json` sans que la doc le
qualifie correctement.
**Dérive trouvée (réelle, prose-fact ungated).** Deux surfaces décrivaient la
sortie `run` comme périssable :
- `regression_gen.py` docstring l.26 : « Sortie NON déterministe → non commitée. »
- `qa/regression/README.md` § hand-off VPS l.76 : « Le mode `run` reste **manuel**
(non déterministe · non gated push/PR). »
**Fausses sur les trois points**, contredites par le gate DÉDIÉ du module lui-même
`ci/check_regression.sh` (= step `check-regression` de `.gitea/workflows/ci.yml`,
confirmé vert) : `regression_run.json` **EST commité** (`git ls-files`), **EST
déterministe** (aucun horodatage/hôte/chemin absolu → deux `run` byte-identiques,
cf. en-tête gate l.24-25) et **EST byte-gaté à chaque push/PR**. C'est exactement
la dérive « regression_run.json non commité » déjà corrigée dans le README **racine**
(commit 76fb0e7, cf. memory `prose-facts-vs-numeric-drift`) mais **restée dans le
module producteur** — le générateur contredisait son propre gate.
**Correctif.** Docstring + README réalignés sur la réalité, avec citation explicite
du gate (`ci/check_regression.sh` / `ci/check_artifacts.sh`). Ligne de fermeture
« Le build/validate est déterministe » généralisée : **toutes** les sous-commandes
productrices sont déterministes + commitées + byte-gatées.
**Consommateur régénéré (`artifact-reproducibility-gate`).** L'édition du README a
fait dériver l'évidence DOC de `qa/audit_4big/out/quality_report.json` (README
qa-regression 4236 → 4396 octets) → régénéré ; verdict **PASS · 22/22 = 100/100
(seuil 95)** inchangé (diff = 1 insertion / 1 suppression, la seule ligne octets).
La docstring `.py` n'est lue en octets par aucun gate → pas d'autre consommateur.
**Gate-neutre.** `./run_ci.sh` → **30 PASS · 0 FAIL · 0 SKIP**. Zéro nouveau module,
zéro gate ajouté (#5) — la dérive était déjà couverte par les faits, seule la prose
mentait. Commit `89eb8e6`.
## Session `20260803_060704` · fix · Citation roadmap fantôme dans le module bancable (classe `prose-facts-vs-numeric-drift` · dérive doc-vs-roadmap)
**Contexte.** Repo tout-vert au démarrage (`run_ci.sh` 30 PASS / 0 FAIL). Sweep
docstring-vs-CODE des 20 générateurs `*_gen.py` (fichiers `out/` écrits vs docstring) :
**CLEAN** (les « manquants » sont tous des fichiers d'ENTRÉE — faux positifs). Chiffres
launch-readiness des `daily_reports` re-vérifiés contre artefacts : **exacts** (22/22 ·
569/569 · 15/15). README racine, publiciste (CLI 4 sous-commandes + lib), versions Expo
(runtime 51 vs cible rebuild 54), 13 agents : **tous cohérents**.
**Dérive trouvée (réelle · ungated · citation mal-attribuée).** Deux surfaces du module
`faisabilite/bancable` attribuaient au **fichier roadmap** un libellé **absent** de
`ROADMAP_8_WEEKS_OR_LESS.md` :
- `bancable_gen.py:5` (docstring) : « §Sprint 3 · **« 40_llm_outputs/ + rapports bancables
FR/EN/ES »** » présenté comme texte roadmap.
- `bancable/README.md:5` : « §Sprint 3 (**« `40_llm_outputs/` + rapports bancables
FR/EN/ES »**) ».
`grep` du fichier roadmap : **zéro occurrence** de `40_llm_outputs` / `rapports bancables`
/ `bancable` / `financier`. Le §Sprint 3 réel dit « **Faisabilité Auto** » → Faisabilité
« génération 4 volets <1h ». Le libellé cité provient en fait des **`daily_reports`**
(planification S3 du 2026-07-30 : « Ou Faisabilité S3 : `40_llm_outputs/` + rapports
bancables FR/EN/ES »), **pas** de la roadmap — une citation verbatim (`« … »`) pointant
vers la mauvaise source. Même classe que la dérive « regression_run.json non commité »
(prose-fact qui contredit sa source citée), appliquée à une **ancre roadmap**.
**Correctif.** Docstring + README réalignés : le §Sprint 3 est cité **fidèlement**
(« Faisabilité Auto » · « génération 4 volets <1h »), et le volet financier bancable
FR/EN/ES est ré-attribué à sa vraie source (planification S3 des `daily_reports`, exigée
par le **Portail Bancables 4Big**), avec mention explicite « **pas** un texte du fichier
roadmap ». Lien README ajouté vers `../../daily_reports`.
**Consommateur régénéré (`artifact-reproducibility-gate`).** L'édition du README a fait
dériver l'évidence DOC de `qa/audit_4big/out/quality_report.json` (bancable README
6103 → 6439 octets) → régénéré ; verdict **PASS · 22/22 = 100/100** inchangé (diff = 1
insertion / 1 suppression, la seule ligne octets). La docstring `.py` n'est lue en octets
par aucun gate → pas d'autre consommateur. Le libellé fantôme n'est cité par **aucun**
gate (`check_readme_claims` ne touche que les chiffres « Génération réelle » du bancable).
**Gate-neutre.** `./run_ci.sh` → **30 PASS · 0 FAIL · 0 SKIP**. Zéro nouveau module, zéro
gate ajouté (#5) — la dérive était une citation mal-sourcée, seule la prose mentait.
## Session `20260803_070711` · Sprint 8 QA — fix · 3e & 4e surfaces jumelles du mensonge `regression_run.json` « non déterministe / non commité »
**Contexte.** Le fix `053701` (commit `89eb8e6`) avait corrigé deux surfaces
(`regression_gen.py` docstring + `qa/regression/README.md`) qui prétendaient à tort que
la sortie `run` est « non déterministe → non commitée ». Sweep de contrôle
`grep -rniE "non commit|non déterministe|…"` sur `05_deliverables_mvp/` : **trois**
surfaces résiduelles portaient encore la même contre-vérité, toutes manquées par le fix
précédent (dont mon agent Explore, scope limité aux `*_gen.py`, ne couvrait pas
`reglib/`) :
1. `reglib/builder.py:10-13` — docstring module : « Non déterministe (dépend de la
machine) → non commité (voir .gitignore) ». **Doublement faux** : pointe vers
`.gitignore` comme autorité alors que le `.gitignore` affirme l'**inverse**
(« `out/regression_run.json` (mode `run`) EST commité … byte-déterministe »).
2. `reglib/builder.py:71` — docstring `run_matrix()` : « destiné à un artefact non
commité ».
3. `regression_gen.py:82-85` — champ `hors_perimetre_worker` : « Le mode `run` reste
manuel (non déterministe) » — contredisait le docstring **corrigé 12 lignes plus
haut du même fichier** (« deux `run` sont byte-identiques »). Ce champ coule dans
`out/MANIFEST.json` **commité** → surface **gatée** par la reproductibilité.
**Preuve ground-truth (4 sources concordantes).** `git ls-files` → `regression_run.json`
est commité · `.gitignore` documente commité+byte-déterministe · `ci/check_regression.sh`
(step `check-regression` de `ci.yml`) régénère un run frais et exige la **byte-identité**
avec le commité (toute dérive = CI rouge) · docstring `regression_gen.py:26` déjà réaligné.
**Correctif.** Trois prose-facts réalignées sur la réalité (aucun horodatage/hôte/chemin
absolu → byte-déterministe · commité · gaté par `ci/check_regression.sh`). Surface #3
(gatée) : `MANIFEST.json` régénéré (`build -o out`, 1 ligne). Plan + `regression_run.json`
**inchangés** (aucun compteur touché). Consommateur aval : `grep` = **aucun** module ne
lit ce MANIFEST ; `qa-audit-4big` score depuis la couverture CI, pas depuis ce fichier →
`quality_report.json` inchangé (confirmé par le gate reproductibilité vert).
**Gate-neutre.** `./run_ci.sh` → **30 PASS · 0 FAIL · 0 SKIP**. Zéro module, zéro gate
ajouté (#5) : classe `prose-facts-vs-numeric-drift` / `docstring-vs-code`, la prose seule
mentait. Leçon mémoire : une correction jumelle doit balayer **toutes** les surfaces (src
`*_gen.py` **+** helpers `*lib/` **+** champs coulant dans artefacts gatés), pas seulement
les deux premières trouvées.
## Session `20260803_073711` · Sprint 5/8 · doc — Canal 2 `daily_reports/` remis à jour (session `070711` manquante)
**Constat d'ouverture (analyse avant action).** Le gate est intégralement vert
(`run_ci.sh` → **30 PASS · 0 FAIL · 0 SKIP**), les 15/15 promesses roadmap sont
`in_repo`, les 22/22 modules à 100/100. Chasse préalable à la dérive **doc-vs-code**
(sous-agent `Explore` sur les 12 modules `*_gen.py` + `*lib/` + README) = **CLEAN**,
zéro contradiction code-adossée. La classe `docstring-vs-code` est bien maintenue.
**Seul écart concret trouvé — Canal 2.** Le snapshot stakeholder
`05_deliverables_mvp/daily_reports/2026-08-03.md` s'arrêtait à l'addendum de la session
`060704` ; la **dernière session commitée** (`070711` · commit `dbde8fa` · 3 surfaces
jumelles résiduelles du mensonge `regression_run.json`) n'y figurait pas. Conforme à la
discipline « deux canaux de log » : chaque livrable stakeholder-pertinent doit
apparaître dans `daily_reports`. La session `063711` (mise à jour Canal 2 elle-même) ne
s'auto-loggue pas — cohérent avec le motif des sessions `043644`/`063711` antérieures.
**Correctif.** Ajout de l'addendum `070711` avant la table launch-readiness (fidèle au
commit `dbde8fa` : 3 surfaces `reglib/builder.py:10-13`/`:71` + `regression_gen.py:82-85`,
ground-truth 4 sources, `MANIFEST.json` régénéré, `regression_run.json` inchangé). Chiffres
du snapshot re-vérifiés contre artefacts commités : verdict `PASS` · **22 modules** ·
**22 suites** · **569 ran/569 passed/0-0-0** — **inchangés**. `daily_reports/` non gaté →
**gate-neutre**. `run_ci.sh` re-vérifié **30 PASS · 0 FAIL**. Commit à suivre.
## Session 080712 · Sprint 8 QA · passe de vérification d'intégrité (Regression exhaustive) — aucune dérive trouvée
**Choix de tâche.** Démarrage : `./run_ci.sh` = **30 PASS · 0 FAIL · 0 SKIP**, arbre
propre. La recette roadmap (`qa/acceptance/out/acceptance_matrix.json`) est **15/15
`in_repo`, verdict `true`** (8 livrables sprint S1→S8 + 7 métriques MVP M1→M7). Aucune
promesse roadmap incomplète, donc pas de tâche de construction disponible. La valeur
in-périmètre restante est la **QA de non-régression exhaustive** (livrable Sprint 8) et la
chasse à la dérive doc-vs-code — sans fabriquer de gate (proscrit #5) ni gonfler un
AGENT.md (les 13 fiches sont auditées exactes, [[fiche-accuracy-audit-closed]]).
**Dimensions vérifiées (toutes CLEAN).**
1. **Roadmap** — 15/15 `in_repo`, verdict `true`.
2. **CI** — 30 jobs (7 gates `ci/*.sh` + 23 suites de module) tous verts.
3. **Dérive docstring-vs-code** (classe [[docstring-vs-code-drift]], marquée RÉCURRENTE) —
sweep Explore exhaustif sur tous les `*_gen.py` + `*lib/` + README de module :
**« CLEAN — no new docstring-vs-code drift »**. Les 4 instances historiques
(publiciste fallback §5.3, demo run_sheet.md, regression `non déterministe/non commité`,
bancable citation fantôme) restent réconciliées.
4. **Chiffres data-derived README racine** — « 22/22 modules gated à 100/100 » re-dérivé de
`qa/audit_4big/out/quality_report.json` (`modules=22`) · « 22 suites gated » et « 569
tests » re-dérivés de `qa/regression/out/{regression_plan,MANIFEST}.json`
(`suites=22`, `test_methods=569`). `check-readme-claims` re-vérifié isolément = **PASS**.
**Signal analysé et écarté (non-dérive).** `run_ci.sh` compte **23** suites de module et
`find …/tests/test_*.py` = **23**, alors que README/daily_reports disent **22**. Réconcilié :
le 23e job CI est le **self-module `qa/regression`**, gaté en CI mais **exclu de sa propre
matrice de régression par SoD** — d'où matrice = 22, jobs CI = 23. Déjà documenté
`ci/README.md:226` (« `self_module` `qa/regression`, exclu de la matrice par SoD mais bien
documenté »). Aucun correctif : « 22 » est le compte correct de la matrice. Piège classique
pour un futur auditeur qui « corrigerait » 22→23 → introduirait un vrai mensonge ; la
distinction est déjà enregistrée dans le repo, donc pas de mémoire à ajouter (ne pas
dupliquer ce que le repo consigne).
**Canal 2.** `daily_reports/2026-08-03.md` couvre jusqu'à la session `070711` ; les sessions
Canal-2 elles-mêmes (`063711`/`073711`) ne s'auto-loguent pas — snapshot **à jour**,
[[two-logging-channels]].
**Réalisé / gate-neutre.** Session de vérification pure : **aucune modification de code,
d'artefact ni de gate** — seule cette entrée Canal 1 est écrite (le log n'est pas gaté).
`run_ci.sh` re-confirmé **30 PASS · 0 FAIL · 0 SKIP** à la clôture. Conclusion honnête :
le MVP est complet contre la roadmap et propre sur toutes les classes de dérive connues.
@@ -129,3 +129,120 @@ invariants** (déterminisme = 15). Schéma étendu (`store_listing` + `$ref`
**Hors périmètre (inchangé · #8).** `eas build`/`eas submit`, assets binaires **Hors périmètre (inchangé · #8).** `eas build`/`eas submit`, assets binaires
(icône/splash 1024²), credentials Apple/Google → agent Mobile (VPS/stores). (icône/splash 1024²), credentials Apple/Google → agent Mobile (VPS/stores).
---
## Addendum · Session `20260803_033642` · Sprint 5 Mobile P1 — workflow CI/CD `mobile-build.yml` (livrable net)
**Tâche exécutée (livrable fonctionnel, périmètre worker).** Création du workflow
Gitea Actions [`.gitea/workflows/mobile-build.yml`](../../.gitea/workflows/mobile-build.yml)
— action **P1 · CI/CD Mobile** explicite de `DIRECTIVE_MOBILE_STORES_20260803.md`
(« Trigger sur push `main` ou tag `v*` · Job iOS/Android `eas build --profile
production --non-interactive` »). Deuxième workflow du repo à côté de `ci.yml`, même
runner Gitea (`ubuntu-latest`) — **jamais GitHub** (`CLAUDE.md` #2).
**Design activation-différée (#6/#8 · zéro credential inventé).** 3 jobs :
`preflight` (toujours vert · vérifie la présence de la config EAS versionnée
`out/eas_build.json` + rapporte l'état des secrets, sans jamais les logger) puis
`build-ios` (App Store #32) et `build-android` (Play Store), **tous deux gardés
`if: secrets.EAS_TOKEN != '' && vars.MOBILE_NATIVE_REPO != ''`** → **SKIP** tant que
Michel n'a pas fourni le token expo.dev + le dépôt Gitea du code natif Expo. **Le CI
n'est donc JAMAIS rendu rouge** avant activation. Aucun identifiant fabriqué : token,
repo natif et credentials Apple/Google restent des secrets/variables `a_confirmer`,
cohérents avec les champs `null · a_confirmer` du livrable mobile.
**Source de vérité versionnée.** Le workflow n'invoque que les profils EAS
(`development`/`preview`/`production`) de `out/eas_build.json` — le code natif Expo
vit dans un dépôt séparé (`/opt/oto/mobile/native/` · Expo 51 → cible 54 roadmap
l.56), **cloné au run** depuis `vars.MOBILE_NATIVE_REPO`, jamais recopié ici.
**Gate-neutre.** Fichier de config CI (hors `out/` byte-gaté, hors `ci/*.sh`) →
`./run_ci.sh` **30 PASS · 0 FAIL · 0 SKIP** inchangé. Le README Mobile documente le
workflow (table périmètre + § CI/CD). **Zéro nouveau module · zéro gate ajouté (#5).**
---
## Addendum · Session `20260803_040643` · Sprint 5 Mobile — fix dérive doc-vs-CODE `cmd_build`
**Correctif de vérité-terrain (classe `docstring-vs-code-drift`, ungated).**
`cmd_build` écrit **5** fichiers (`app_config`, `eas_build`, `role_navigation`,
`store_listing`, `MANIFEST``app_config_gen.py:239-243`), mais deux surfaces de doc
décrivaient encore **4**, le `store_listing.json` (ajouté après coup en session
`030641`) y étant omis : docstring `app_config_gen.py:20` (« les **4** fichiers » vs
énumération l.11-17 qui liste bien 5) + glob `README.md` § Utilisation
(`store_listing` absent). Réalignés sur **5**.
**Consommateur régénéré (byte-repro · `artifact-reproducibility-gate`).** L'édition
du README a fait dériver le byte-count DOC de
[`qa/audit_4big/out/quality_report.json`](../qa/audit_4big/out/quality_report.json)
(README Mobile 4917 → 4931 octets) → régénéré ; verdict **PASS · 22/22 ≥ 95 (min
100)** inchangé (1 insertion / 1 suppression). `./run_ci.sh` **30 PASS · 0 FAIL**.
## Addendum · Session `20260803_050654` · Sprint 1 DevOps — `ci/README.md` complété (2e workflow)
**Complétude doc CI/CD (classe `prose-facts-vs-numeric-drift`).** Depuis l'ajout de
`.gitea/workflows/mobile-build.yml` (commit `af84b21`), le dépôt possède **deux**
workflows Gitea Actions, mais le livrable CI/CD `ci/README.md` § 1 ne mentionnait que
`ci.yml` (référence à sens unique : `mobile-build.yml` pointe vers `ci/README.md`, pas
l'inverse). Nouvelle sous-section « `mobile-build.yml` (HORS gate de merge) » : vérifié
par construction hors `gate.needs` (`check-ci-integrity` ne verrouille que `ci.yml`),
même runner, **SKIP-safe** sans `EAS_TOKEN`. Prose éditoriale sans chiffre data-derived
**gate-neutre**. Commit `1af5d01`.
## Addendum · Session `20260803_053701` · Sprint 8 — fix dérive doc-vs-réalité `regression_run.json`
**Correctif prose-fact ungated (jumelle du fix root-README).** Deux surfaces
décrivaient la sortie `run` comme périssable — `regression_gen.py` docstring l.26
(« Sortie NON déterministe → non commitée ») + `qa/regression/README.md` § hand-off
l.76 (« mode `run` … non déterministe · non gated ») — **fausses** : le générateur
contredisait son propre gate dédié `ci/check_regression.sh` (step `check-regression`
de `ci.yml`). En réalité `regression_run.json` **EST** commité, déterministe et
byte-gaté à chaque push/PR. Docstring + README réalignés sur la réalité avec citation
du gate. Consommateur [`quality_report.json`](../qa/audit_4big/out/quality_report.json)
régénéré (README qa-regression 4236 → 4396 o) · verdict **PASS · 22/22** inchangé.
Commits `89eb8e6` (fix) + `3d8ccb0` (log).
## Addendum · Session `20260803_060704` · Sprint 3 — fix citation roadmap fantôme (module bancable)
**Citation mal-attribuée (classe `prose-facts-vs-numeric-drift`).** `bancable_gen.py:5`
+ `faisabilite/bancable/README.md:5` attribuaient au **fichier roadmap** un libellé
verbatim (« `40_llm_outputs/` + rapports bancables FR/EN/ES ») **absent** de
`ROADMAP_8_WEEKS_OR_LESS.md` (grep = 0 occurrence). Le §Sprint 3 réel dit
« **Faisabilité Auto** · génération 4 volets <1h » ; le libellé cité venait en fait des
`daily_reports` (planification S3 du 2026-07-30), pas de la roadmap. Docstring + README
réalignés : §Sprint 3 cité fidèlement, volet financier bancable ré-attribué à sa vraie
source (planif S3 · Portail Bancables 4Big). Consommateur
[`quality_report.json`](../qa/audit_4big/out/quality_report.json) régénéré (bancable
README 6103 → 6439 o) · verdict **PASS · 22/22** inchangé. Commit `88d9955`.
## Addendum · Session `20260803_070711` · Sprint 8 QA — 3 surfaces jumelles résiduelles `regression_run.json`
**Balayage complet du même mensonge (classe `prose-facts-vs-numeric-drift` /
`docstring-vs-code`).** Le fix `89eb8e6` (session `053701`) avait réaligné le docstring
principal + le README, mais la même contre-vérité (« sortie `run` non déterministe →
non commitée ») subsistait dans **3 surfaces manquées** par le premier passage :
`reglib/builder.py:10-13` (docstring module — citait le `.gitignore` comme autorité
alors qu'il affirme l'**inverse**), `reglib/builder.py:71` (docstring `run_matrix`) et
`regression_gen.py:82-85` (champ `hors_perimetre_worker` qui **coule dans**
`MANIFEST.json` commité + gaté, contredisant le docstring corrigé 12 lignes plus haut).
Ground-truth croisé sur **4 sources commitées** : `git ls-files` · `.gitignore` ·
`ci/check_regression.sh` (exige la byte-identité d'un run frais) · docstring
`regression_gen.py:26` déjà réaligné. `MANIFEST.json` régénéré (build) ; `plan` +
`regression_run.json` **inchangés** · aucun consommateur aval · **gate-neutre**.
`run_ci.sh`**30 PASS · 0 FAIL**. Commit `dbde8fa`. Leçon consignée : un fix jumeau
doit balayer **toutes** les surfaces en un seul passage (mémoire
`prose-facts-vs-numeric-drift`).
## État launch-readiness · fin de journée (inchangé · 100 % sourcé)
| Dimension | Valeur | Verdict | Source commitée |
|---|---|---|---|
| Qualité 4Big | **22/22 modules à 100/100** (seuil 95) | `PASS` | [`qa/audit_4big/out/quality_report.json`](../qa/audit_4big/out/quality_report.json) |
| Régression (run) | **22 suites · 569 ran · 569 passés · 0/0/0** | `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) |
| CI/CD Mobile (P1) | workflow `mobile-build.yml` · 3 jobs · SKIP-safe sans `EAS_TOKEN` | vert | [`.gitea/workflows/mobile-build.yml`](../../.gitea/workflows/mobile-build.yml) |
| Miroir local | `run_ci.sh`**30 PASS · 0 FAIL · 0 SKIP** | vert | [`run_ci.sh`](../../run_ci.sh) |
**Hors périmètre (inchangé · #8).** Exécution serveur `eas build`/`eas submit` (attend
`EAS_TOKEN` Michel + `MOBILE_NATIVE_REPO`), déploiement production VPS → agents
Mobile/DevOps.
@@ -2,7 +2,11 @@
> Livrable **Faisabilité · Sprint 3** — roadmap > Livrable **Faisabilité · Sprint 3** — roadmap
> [`ROADMAP_8_WEEKS_OR_LESS.md`](../../../04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md) > [`ROADMAP_8_WEEKS_OR_LESS.md`](../../../04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md)
> §Sprint 3 (« `40_llm_outputs/` + rapports bancables FR/EN/ES »). > §Sprint 3 « Faisabilité Auto » (Faisabilité → « génération 4 volets <1h »). Le volet
> **financier bancable FR/EN/ES** est la déclinaison S3 planifiée dans les
> [`daily_reports`](../../daily_reports) (« `40_llm_outputs/` + rapports bancables
> FR/EN/ES ») — un libellé de planification, **pas** un texte du fichier roadmap —
> exigée par le **Portail Bancables 4Big** (ci-dessous).
Remplit le répertoire `50_financier_bancable/` d'une data_room — jusqu'ici **vide** Remplit le répertoire `50_financier_bancable/` d'une data_room — jusqu'ici **vide**
(`.gitkeep` posé par le générateur 4 volets) — que le **Portail Bancables 4Big** (`.gitkeep` posé par le générateur 4 volets) — que le **Portail Bancables 4Big**
@@ -2,7 +2,10 @@
"""Générateur de dossier financier bancable trilingue FR/EN/ES · Sprint 3. """Générateur de dossier financier bancable trilingue FR/EN/ES · Sprint 3.
Livrable **Faisabilité · Sprint 3** (roadmap `04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md` Livrable **Faisabilité · Sprint 3** (roadmap `04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md`
§Sprint 3 · « 40_llm_outputs/ + rapports bancables FR/EN/ES »). Remplit le §Sprint 3 « Faisabilité Auto » → Faisabilité « génération 4 volets <1h » ; le volet
**financier bancable FR/EN/ES** est la déclinaison S3 planifiée dans les
`daily_reports` — « 40_llm_outputs/ + rapports bancables FR/EN/ES » — et exigée par le
Portail Bancables 4Big, non un libellé du fichier roadmap). Remplit le
répertoire `50_financier_bancable/` d'une data_room — jusqu'ici vide (`.gitkeep`) répertoire `50_financier_bancable/` d'une data_room — jusqu'ici vide (`.gitkeep`)
— que le **Portail Bancables 4Big** (`PORTAIL_BANCABLES_4BIG.md`, variante 06 — que le **Portail Bancables 4Big** (`PORTAIL_BANCABLES_4BIG.md`, variante 06
retenue par Michel) exige à l'étape 1 de son workflow de déploiement projet. retenue par Michel) exige à l'étape 1 de son workflow de déploiement projet.
@@ -19,6 +19,14 @@ produit uniquement la **config** que l'agent Mobile consomme sur le poste/CI EAS
| `app.config` Expo (thème, locales, navigation) | `eas build` (Expo 54) | | `app.config` Expo (thème, locales, navigation) | `eas build` (Expo 54) |
| `eas.json` (profils build/submit) | `eas submit` App Store #32 / Play Store | | `eas.json` (profils build/submit) | `eas submit` App Store #32 / Play Store |
| navigation par rôle (gating RBAC) | credentials / signing / assets binaires | | navigation par rôle (gating RBAC) | credentials / signing / assets binaires |
| workflow CI/CD `.gitea/workflows/mobile-build.yml` (Sprint 5 P1) | exécution `eas build` sur runner EAS |
**CI/CD Mobile (Sprint 5 P1 · directive `DIRECTIVE_MOBILE_STORES_20260803.md`).** Le
workflow Gitea Actions [`.gitea/workflows/mobile-build.yml`](../../../.gitea/workflows/mobile-build.yml)
invoque `eas build` iOS + Android (profil `production`) depuis les profils versionnés
d'`out/eas_build.json`. Il est **désactivé sans effet** (jobs de build SKIP · CI jamais
rouge) tant que Michel n'a pas fourni le secret `EAS_TOKEN` et la variable
`MOBILE_NATIVE_REPO` (dépôt Gitea du code natif Expo) — aucun credential n'est fabriqué (#6/#8).
## Zéro invention (#6) ## Zéro invention (#6)
@@ -45,7 +53,7 @@ Publiciste (zéro `pip`).
## Utilisation ## Utilisation
```bash ```bash
python3 app_config_gen.py build # écrit out/{app_config,eas_build,role_navigation}.json + MANIFEST.json python3 app_config_gen.py build # écrit out/{app_config,eas_build,role_navigation,store_listing}.json + MANIFEST.json
python3 app_config_gen.py validate # schéma + 15 invariants (sort en erreur sinon) python3 app_config_gen.py validate # schéma + 15 invariants (sort en erreur sinon)
python3 -m unittest discover -s tests -v python3 -m unittest discover -s tests -v
``` ```
@@ -17,7 +17,7 @@ en :
- MANIFEST.json -> traçabilité (comptes, résumé par portail, marque, a_confirmer) - MANIFEST.json -> traçabilité (comptes, résumé par portail, marque, a_confirmer)
Sous-commandes : Sous-commandes :
build [-o OUT] -> écrit les 4 fichiers ci-dessus build [-o OUT] -> écrit les 5 fichiers ci-dessus
validate [-o OUT] -> (re)génère en mémoire, valide vs mobile.schema.json + invariants validate [-o OUT] -> (re)génère en mémoire, valide vs mobile.schema.json + invariants
Sortie déterministe (tri stable, aucun horodatage) -> diffable + re-générable. Sortie déterministe (tri stable, aucun horodatage) -> diffable + re-générable.
@@ -318,7 +318,7 @@
"criterion": "DOC", "criterion": "DOC",
"weight": 20, "weight": 20,
"passed": true, "passed": true,
"evidence": "README.md (6103 octets)" "evidence": "README.md (6439 octets)"
}, },
{ {
"criterion": "CONTRAT", "criterion": "CONTRAT",
@@ -606,7 +606,7 @@
"criterion": "DOC", "criterion": "DOC",
"weight": 20, "weight": 20,
"passed": true, "passed": true,
"evidence": "README.md (4261 octets)" "evidence": "README.md (4931 octets)"
}, },
{ {
"criterion": "CONTRAT", "criterion": "CONTRAT",
@@ -900,7 +900,7 @@
"criterion": "DOC", "criterion": "DOC",
"weight": 20, "weight": 20,
"passed": true, "passed": true,
"evidence": "README.md (4236 octets)" "evidence": "README.md (4396 octets)"
}, },
{ {
"criterion": "CONTRAT", "criterion": "CONTRAT",
+5 -3
View File
@@ -71,9 +71,11 @@ rejoue que `build` (déterministe) et **ignore** cet artefact d'exécution.
## Hand-off VPS (hors périmètre worker · #8) ## Hand-off VPS (hors périmètre worker · #8)
Planifier `run` sur le runner CI/VPS et publier le compte agrégé dans le desk Publier le compte agrégé dans le desk ERPNext / le pipeline de release → agent
ERPNext / le pipeline de release → agent **QA / DevOps**. Le mode `run` reste **QA / DevOps**. Le `run` lui-même n'est PAS manuel côté worker : sa sortie
**manuel** (non déterministe · non gated push/PR), comme la baseline E2E. `regression_run.json` est **déterministe** (aucun horodatage/hôte) donc commitée
et **byte-gatée à chaque push/PR** par `ci/check_regression.sh`. Ce qui reste
hors périmètre (#8), c'est sa **publication** VPS (desk / release).
## Auto-score 4Big ## Auto-score 4Big
@@ -11,5 +11,5 @@
"regression_plan.json" "regression_plan.json"
], ],
"roadmap": "Sprint 8 · QA · Regression tests exhaustifs", "roadmap": "Sprint 8 · QA · Regression tests exhaustifs",
"hors_perimetre_worker": "Exécution planifiée de `run` sur le runner CI/VPS + publication du compte agrégé dans le desk ERPNext / le pipeline de release → agent QA / DevOps (#8). Le mode `run` reste manuel (non déterministe)." "hors_perimetre_worker": "Exécution planifiée de `run` sur le runner CI/VPS + publication du compte agrégé dans le desk ERPNext / le pipeline de release → agent QA / DevOps (#8) : hors périmètre car planifiée sur le runner/VPS, non parce que la sortie dériverait — `regression_run.json` est byte-déterministe · commité · gaté par `ci/check_regression.sh`."
} }
@@ -8,9 +8,10 @@ Deux artefacts, deux natures :
Verdict PASS ssi couverture prouvée + chaque suite ≥ planchers. Verdict PASS ssi couverture prouvée + chaque suite ≥ planchers.
run → MATRICE live : exécute réellement chaque suite et agrège les compteurs run → MATRICE live : exécute réellement chaque suite et agrège les compteurs
(ran/passed/failures/errors/skipped) + verdict global. Non déterministe (ran/passed/failures/errors/skipped) + verdict global. Aucun horodatage /
(dépend de la machine) → non commité (voir .gitignore), c'est la sortie hôte / chemin absolu → deux `run` sont byte-identiques : l'artefact
qui fait autorité sur « N tests verts ». `regression_run.json` EST commité et byte-gaté par `ci/check_regression.sh`
(voir .gitignore), c'est la sortie qui fait autorité sur « N tests verts ».
Aucune date/horodatage → build reproductible (gate CI stable).""" Aucune date/horodatage → build reproductible (gate CI stable)."""
@@ -68,7 +69,8 @@ def build_plan(spec: dict[str, Any]) -> dict[str, Any]:
def run_matrix(spec: dict[str, Any], *, python: str | None = None) -> dict[str, Any]: def run_matrix(spec: dict[str, Any], *, python: str | None = None) -> dict[str, Any]:
"""Exécute réellement toutes les suites du plan et agrège les compteurs. """Exécute réellement toutes les suites du plan et agrège les compteurs.
Non déterministe (temps, machine) → destiné à un artefact non commité.""" Byte-déterministe (aucun horodatage/hôte/chemin absolu) → l'artefact
`regression_run.json` EST commité et byte-gaté par `ci/check_regression.sh`."""
suites = discovery.discover_suites(spec) suites = discovery.discover_suites(spec)
discover_cmd = list(spec["discover_cmd"]) discover_cmd = list(spec["discover_cmd"])
# `python3 -m unittest ...` → on retire le binaire, on garde les args. # `python3 -m unittest ...` → on retire le binaire, on garde les args.
@@ -23,9 +23,15 @@ Sous-commandes :
suite passe sous les planchers structurels. suite passe sous les planchers structurels.
run [-o OUT] → exécute réellement toutes les suites, agrège la matrice run [-o OUT] → exécute réellement toutes les suites, agrège la matrice
live + verdict ; sort en erreur (code ≠ 0) si une suite est live + verdict ; sort en erreur (code ≠ 0) si une suite est
rouge. Sortie NON déterministe → non commitée. rouge. Écrit `regression_run.json` : bien qu'il porte les
compteurs réellement exécutés, il ne contient AUCUN
horodatage/hôte/chemin absolu → deux `run` sont
byte-identiques, donc l'artefact EST commité et byte-gaté
par `ci/check_regression.sh` (toute dérive = CI rouge).
Le `build`/`validate` est déterministe (tri stable, aucun horodatage) → diffable. Toutes les sous-commandes productrices sont déterministes (tri stable, aucun
horodatage) → artefacts diffables + commités + byte-gatés : `regression_plan.json`
par `ci/check_artifacts.sh`, `regression_run.json` par `ci/check_regression.sh`.
""" """
from __future__ import annotations from __future__ import annotations
@@ -76,7 +82,9 @@ def _manifest(spec: dict, plan: dict) -> dict:
"hors_perimetre_worker": ( "hors_perimetre_worker": (
"Exécution planifiée de `run` sur le runner CI/VPS + publication du " "Exécution planifiée de `run` sur le runner CI/VPS + publication du "
"compte agrégé dans le desk ERPNext / le pipeline de release → agent " "compte agrégé dans le desk ERPNext / le pipeline de release → agent "
"QA / DevOps (#8). Le mode `run` reste manuel (non déterministe)." "QA / DevOps (#8) : hors périmètre car planifiée sur le runner/VPS, "
"non parce que la sortie dériverait — `regression_run.json` est "
"byte-déterministe · commité · gaté par `ci/check_regression.sh`."
), ),
} }
+274
View File
@@ -0,0 +1,274 @@
# OTO Design System v1 · 2026-08-03
**Statut** · référence canonique · à respecter par tous les agents Claude Code DTP, ERPNext IA, OTOIA, sous-agents web/mobile/print/PDF.
**Portée** · site public vente.otov7.com, portail client /mon-compte/, console admin, applications mobiles iOS/Android, documents PDF (Trousse Client, Promesa, brochures, kit banquier).
## 1. Marque
### Identités visuelles officielles
- **World Activities Group (WAG)** · marque holding · logo `WA·official.png` avec 3 buildings dorés stylisés
- **HELIOS RD** · marque publique immobilière sous WAG · logo helios avec soleil abstrait
- **AC · Arias Cuevas SRL** · division construction · logo AC-official.png
- **Consortium ECR DR** · paymaster RH · logo ECR-official.png
- **9060 QC (World Activities Cdn.)** · entité canadienne 9060-2111
- **OTO CONCIERGE** · service client · silhouette majordome cercle doré (voir /static/oto-concierge-logo.png)
### Anciens logos INTERDITS
Ne jamais utiliser les versions historiques "WA-v1", "heliosroy-logo", "WA-triangle". Toujours privilégier les *-official.png.
## 2. Palette couleurs
### Palette site public + PDF
- **Fond principal** · `#0A0A0E` (noir profond, très légèrement bleuté)
- **Or accent** · `#C9A465` (or premium mat, principal)
- **Or lumineux hover** · `#e6c17f` (or doré clair pour hover)
- **Or halo/glow** · `#ffd66a` (or vif pour effets)
- **Texte principal** · `#FAF8F4` (blanc cassé chaleureux)
- **Texte secondaire** · `rgba(250,248,244,0.72)` (subtle)
- **Texte tertiaire** · `rgba(250,248,244,0.5)`
- **Bordures subtiles** · `rgba(255,255,255,0.08)`
- **Bordures dorées** · `rgba(201,164,101,0.3)` à `rgba(201,164,101,0.5)`
### Palette console admin dark
- Fond · `#0a0a12`
- Or accent · `#f0b429` (or plus vif qu'en public)
- Icônes/dividers · `rgba(255,255,255,0.1)`
### États sémantiques
- Succès · `#25D366` (vert WhatsApp)
- Warning · `#f59e0b` (ambre)
- Erreur · `#ef4444` (rouge doux)
- Info · `#3b82f6` (bleu)
- Muted · `#6b7280` (gris)
### Interdictions couleurs
- ❌ Pas de blancs purs `#FFFFFF` (préférer `#FAF8F4`)
- ❌ Pas de noirs purs `#000000` (préférer `#0A0A0E`)
- ❌ Pas de couleurs saturées primaires (rouge/bleu/vert vif) sauf états sémantiques
## 3. Typographie
### Hiérarchie
- **Titres majeurs** · `Cormorant Garamond` (300-500), fallback `Playfair Display`, fallback Georgia serif
- **Titres décoratifs** · `Cormorant Garamond` italic ou `Playfair Display` italic pour emphase
- **Body texte** · `Inter` (300-500), fallback system-ui, -apple-system, sans-serif
- **Nav / boutons / meta** · `Inter` (600-700) letterspacing 1.5-3px uppercase
- **Chiffres élégants** · `Fraunces` ou `Cormorant Garamond`
- **Monospace (code)** · SF Mono / Menlo (rarissime dans le luxury)
### Règle du "j"
Le caractère "j" doit être bien rendu · **Cormorant Garamond prioritaire** (queue courbée élégante). Playfair Display en fallback (queue moins jolie mais acceptable). **Éviter Fraunces pour "j" majeurs** (queue trop courte).
### Tailles typiques (rem/px)
- Hero title · `clamp(48px, 8vw, 96px)` weight 300
- Section title · `clamp(32px, 4vw, 56px)` weight 300 italic decorative
- Card title · `22-28px` weight 400-500
- Body · `14-17px` line-height 1.6-1.7
- Small/caption · `11-13px` letter-spacing 1.5-2.5px
### Import Google Fonts (par toutes pages)
```html
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400;1,500&family=Fraunces:wght@200;300;400;500&family=Playfair+Display:ital,wght@0,400;0,500;0,600;1,400;1,500&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
```
## 4. Registre et ton d'écriture
### Style obligatoire · Big 4 institutionnel (Deloitte / Christie's Real Estate)
- Ton chaleureux mais professionnel institutionnel
- Vocabulaire soutenu · patrimoine, résidence, adresse, héritage, art de vivre, cadence, prestige
- Éviter les tournures marketing agressives ou commerciales
### Interdictions ABSOLUES écriture
- ❌ Emojis (aucun symbole unicode 😀🎉📱)
- ❌ Astérisques markdown en public (`**gras**`)
- ❌ Listes à puces trop chargées
- ❌ Points d'exclamation multiples
- ❌ Ton familier ou tutoiement dans les documents officiels
- ❌ Anglicismes injustifiés ("appartement" pas "apartment")
### Séparateur privilégié
Le middle dot ` · ` (Alt+Shift+9 macOS) sépare les éléments courts avec plus d'élégance que la virgule ou le tiret. Ex " · disponible · vue mer · 3 chambres · dès 145 000 USD ".
### Vocabulaire clientèle
Systématiquement adapter selon la clientèle cible du projet (défini dans les faisabilités) ·
- Ultra-luxe international · "résidence d'exception", "villégiature", "art de vivre caribéen"
- Bajo Costo local · "logement social qualitatif", "projet résidentiel familial"
- Investisseur · "opportunité patrimoniale", "actif immobilier", "rendement locatif"
## 5. Nomenclature standard OTOV7
### Typologies unités (JAMAIS T1/T2/T3 côté client)
- **Studio** (0 chambre)
- **1 Chambre**
- **2 Chambres**
- **3 Chambres**
- **Penthouse**
### Suffixes gamme
- Standard · gamme base
- Confort · gamme milieu
- Prestige · gamme haute
- Panorama · gamme premium (vue exceptionnelle)
### Codes projets
- P01 Coralis · P02 Coral del Sur · P03 Nakua · P04 Xamaná Cantiles · P05 Las Colinas Najayo Arriba · P06 Coco Real · P07 Aqua Terra · P08 Fasano Espirilla · P09 Résidence Gazcue
## 6. Composants UI
### CTA principal
```html
<button style="background:#C9A465;color:#0A0A0E;padding:16px 32px;font-size:13px;font-weight:700;letter-spacing:2px;text-transform:uppercase;border-radius:4px;border:none;cursor:pointer;">Concierge · à votre écoute</button>
```
### CTA secondaire (ghost)
```html
<button style="background:transparent;color:#C9A465;border:1px solid #C9A465;padding:16px 32px;font-size:13px;font-weight:700;letter-spacing:2px;text-transform:uppercase;border-radius:4px;cursor:pointer;">Découvrir</button>
```
### Panel/Card
```html
<div class="panel" style="background:rgba(255,255,255,0.03);border:1px solid rgba(201,164,101,0.3);border-radius:8px;padding:32px 28px;">
<h3 style="color:#C9A465;font-size:14px;letter-spacing:2px;text-transform:uppercase;margin-bottom:16px;">Titre section</h3>
...
</div>
```
### Input formulaire
```html
<input type="text" style="background:rgba(255,255,255,0.05);border:1px solid rgba(201,164,101,0.25);color:#FAF8F4;padding:12px 14px;border-radius:4px;font-size:14px;">
```
### Badge état
```html
<span style="padding:4px 10px;background:#25D36622;color:#25D366;border:1px solid #25D36655;border-radius:12px;font-size:11px;letter-spacing:1px;text-transform:uppercase;font-weight:600;">Disponible</span>
```
### Widget devise + langue (toujours transparent, top-right)
Fond transparent, texte doré avec double text-shadow pour lisibilité sur tout fond. Soulignement doré fin sur l'actif (pas de fond doré plein). Voir `devise-switch-v7.js`.
### Bandeau pré-commercialisation
Fond transparent + padding 26px 24px + texte doré. Voir `waitlist-banner.js`.
### Concierge silhouette bottom-right
Position fixe bottom:125px right:125px, image PNG 110px transparent (voir `concierge-icon.js`).
## 7. Accessibilité (WCAG 2.1 AA)
### Obligatoires sur toutes pages
- `<html lang="fr">` (ou en/es selon langue active)
- **Skip link** "Aller au contenu principal" visible au focus, position off-screen
- **Focus visible** · outline 2px `#C9A465` sur tous éléments focusables
- Alt text sur toutes images (nom fichier + contexte projet minimum)
- Contraste texte principal (#FAF8F4 sur #0A0A0E) · 15.8:1 (AAA+)
- Contraste texte or (#C9A465 sur #0A0A0E) · 7.8:1 (AAA)
- Boutons min 44×44px zone tactile mobile
- Formulaires · label associé + placeholder complémentaire pas remplaçant
## 8. Multi-langue (FR/EN/ES trilingue)
### Fichiers i18n
- `/opt/oto/sites/vente/i18n/{fr,en,es}.json`
- Attribut HTML `data-i18n="clé"` pour texte à traduire
- Widget devise/langue déclenche `location.href = url + '?lang=xx'` (reload propre + cookie otov7_lang)
### Espagnol · variante République Dominicaine
- Utiliser `es-DO` comme locale principale (pas `es-ES`)
- Vocabulaire · "apartamento" (pas "piso"), "parqueadero" (pas "aparcamiento")
- Devise RD$ (pesos dominicains) + format `1.234.567`
### Anglais · variante US
- `en-US` (pas en-GB)
- Vocabulaire · "apartment" (pas "flat"), "condominium", "downpayment", "escrow"
- Format prix `$145,000`
## 9. Voix OTOIA (synthèse vocale)
### Ordre priorité par langue
- **FR** · fr-CA Nicolas Enhanced → fr-FR Thomas Enhanced → fallback fr-* Neural
- **EN** · en-US Nathan Enhanced → en-US Evan → en-US Aaron → en-US Alex (NEVER en-GB Daniel/UK)
- **ES** · es-DO Diego → es-US → es-PR → es-MX (Latino/Caribbean naturel)
### Pré-processing texte avant TTS (cleanForTTS)
- `·``,` (pause naturelle)
- Em/en dash → `,`
- `HELIOS``Elios` (prononciation)
- `WAG``W A G` épelé
- `R+20``R plus 20`
- Acronymes CONFOTUR/INVI/DGII/IFRS/ISA → épelés lettre par lettre
- Emojis strippés
### Cible qualité premium
ElevenLabs Amélie multilingual_v2 quand token dispo. Pour l'instant · voix native macOS Enhanced/Premium.
## 10. Design mobile
### Applications natives (Expo)
- App name · `OTOv7` (marque World Activities Group)
- Bundle · `com.otov7.app` (iOS + Android)
- Icône · fond noir `#000000` + logo bronze `#f5b04a` + typo Fraunces ("OTO" droit + "v7" italique) + tagline WORLD ACTIVITIES GROUP en Inter
- Splash · variantes light/dark
- Navigation · bottom tabs 4-5 onglets max
### Portail client mobile
Mêmes onglets que /mon-compte/ web · Profil / Unités / Documents / Paiements / Financement / Chantier / SAV / HOA
## 11. Documents PDF (Trousse Client, Promesa, Brochures, Kit Banquier)
### Format et présentation
- Format `Letter US` (215.9×279.4mm) · pas A4
- Marges 25.4mm / 20.32mm (1 inch / 0.8 inch)
- Header · logo entité (WA-official ou HELIOS ou AC selon contexte) + numéro projet
- Footer · WORLD ACTIVITIES, S.R.L. · RNC 1-31-91989-8 · Calle Las Orquídeas No. 18, Mirador del Oeste, Santo Domingo Oeste, RD 10608 · +1 (849) 517-2355 · vente@otov7.com · Page X/Y
### Signatures Certification Ley 126-02
Bordure dorée fine, fond crème `#faf8f4`, checkbox "He leído · He comprendido · Acepto" plus ligne signature + date pré-remplie.
## 12. Écrans admin console
### Layout
- Sidebar gauche 240px dark
- Header top 64px avec logo WA + user menu
- Body scrollable avec padding 32px
- Cards en grid responsive 3-4 colonnes desktop, stack mobile
## 13. Interdictions absolues design
- ❌ Pas de gradients arc-en-ciel ou saturés (rester monochrome noir+or)
- ❌ Pas d'animations bounce/wobble/rotate ridicules
- ❌ Pas de material design Google flat (rester textural luxury)
- ❌ Pas d'ombres portées noires massives (préférer ombres or subtiles `0 0 20px rgba(201,164,101,0.15)`)
- ❌ Pas de border-radius rond exagéré (max 8-12px pour cartes, 20-24px pour pastilles seulement)
- ❌ Pas de tables avec fond alterné bleu/blanc (rester subtil rgba(255,255,255,0.02))
## 14. Références externes visuelles
Style à répliquer selon projet ·
- **Christie's Real Estate** · https://www.christiesrealestate.com/ (référence marque)
- **The Modern House UK** · https://www.themodernhouse.com/
- **The Agency** · https://www.theagencyre.com/
- **Fasano Hotels** (P08 branding partner) · https://www.fasano.com.br/
- **Aman Resorts** · https://www.aman.com/ (ultra luxe minimaliste)
## 15. Fichiers canoniques sur VPS
- Design system (ce document) · `/opt/oto/docs/design/OTO_DESIGN_SYSTEM_v1.md`
- Logos officiels · `/opt/oto/sites/vente/static/logos/*-official.png`
- Concierge assets · `/var/www/html/static/oto-concierge-logo.png` + `oto-concierge-icon.png`
- Scripts UI canoniques · `/var/www/html/static/devise-switch-v7.js` `waitlist-banner.js` `contact-modal.js` `concierge-icon.js` `oto-living-banner.js` `cookies-banner-v2.js` `consent-mode-v2.js`
## 16. Références projet mémoire
Design system connecté à ·
- `otov7_directive_experience_client_premium`
- `otov7_console_design_dark_gold`
- `otov7_signature_brand`
- `otov7_style_deloitte`
- `otov7_nomenclature_typologies_standard`
- `otov7_directive_workflow_documentaire_20260801`
---
**Version** · v1 · 2026-08-03
**Auteur** · Michel Roy (Co-Président WAG)
**Prochaine révision** · à chaque évolution majeure marque
**Consommateurs** · tous agents Claude Code DTP, ERPNextIA, OTOIA, sous-agents web/mobile/PDF/print
+15
View File
@@ -26,6 +26,21 @@ et manuellement (`workflow_dispatch`). Jobs statiques (+ une suite `unittest` pa
Aucune dépendance réseau/marketplace hors `actions/checkout`. Tout tourne avec Aucune dépendance réseau/marketplace hors `actions/checkout`. Tout tourne avec
`bash` + `git` + `python3` (déjà présents sur un runner standard). `bash` + `git` + `python3` (déjà présents sur un runner standard).
### Second workflow Gitea Actions — `mobile-build.yml` (HORS gate de merge)
Le dépôt versionne un **second** workflow Gitea Actions,
[`.gitea/workflows/mobile-build.yml`](../.gitea/workflows/mobile-build.yml)
(livrable Mobile · roadmap Sprint 5 · CI/CD mobile EAS), qui **n'appartient pas
au gate de merge** décrit ci-dessus. C'est volontaire et vérifié par construction :
`check-ci-integrity` ne verrouille **que** `ci.yml` (variable `CI=` du script), et
**aucun** de ses jobs n'est câblé dans `gate.needs` — il ne conditionne donc aucun
merge et `run_ci.sh` ne le rejoue pas (hors `gate.needs`). Il tourne sur le **même
runner** que `ci.yml` et reste **SKIP-safe** : tant que le secret `EAS_TOKEN` n'est
pas fourni par Michel, ses jobs de build (`eas build`/`eas submit`) sont en SKIP —
il ne rend **jamais** le CI rouge (`preflight` reste vert et rapporte les secrets
attendus). Périmètre complet (#8 · exécution serveur hors repo), profils EAS et
variables `a_confirmer` : [`README` du module Mobile](../05_deliverables_mvp/mobile/app_config/README.md).
### Rejouer le gate EN LOCAL — `run_ci.sh` (racine du dépôt) ### Rejouer le gate EN LOCAL — `run_ci.sh` (racine du dépôt)
Avant de committer, reproduire l'intégralité du gate de merge en une commande : Avant de committer, reproduire l'intégralité du gate de merge en une commande :