[DTP-Worker] Sprint 8 · buffer · Fiches agents/colonne « Job CI » : chaque table de livrables de 03_agents/*/AGENT.md NOMME entre backticks le job Gitea Actions qui exécute la suite du module (rbac-tests · fiscal-ecf-tests · frontend-portails-tests…) — nom SAISI À LA MAIN dont la source de vérité est la clé jobs: de .gitea/workflows/ci.yml — mais AUCUN gate ne liait le NOM écrit dans la fiche au job réel. check_ci_integrity.sh prouve que chaque job est CÂBLÉ dans gate.needs (INV-A/B) et les blocs amont de check_readme_claims recomputent les COMPTES de tests par suite ; RIEN ne vérifiait que le token DÉSIGNE un job existant. Renommer un job dans ci.yml (rbac-tests→rbac-role-tests) ou mal recopier demo-scenario-tests en demo-scenarios-tests laissait la fiche pointer un job FANTÔME pendant que le CI reste VERT (le vrai job tourne sous son nouveau nom) — la doc d'identité de l'agent ment en silence.
Gate ajouté (bloc « Fiches agents · colonne Job CI ») : on RECOMPUTE l'ensemble des jobs depuis la clé `jobs:` de ci.yml (la section `on:` push/pull_request/workflow_dispatch est AVANT `jobs:` et donc exclue ; jamais une liste à la main) et on exige que chaque token `*-tests` cité dans une fiche y figure. Direction fiche→ci.yml (le consommateur) : ci.yml peut définir des jobs non cités (légitime), une fiche ne peut pas citer un job absent ; la disparition totale de la colonne échoue AUSSI. 33 références vérifiées == jobs ci.yml ; 2 morsures (token de fiche `seo-tests`→`seo-suite-tests` fantôme · job ci.yml `rbac-tests` renommé → mord SIMULTANÉMENT les 4 fiches qui le citent : erpnext_backend/ifc_speckle/mobile/rendu), restauré vert, 7 gates re-verts. ci/README.md + activity log MAJ. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -414,3 +414,46 @@ contrat · exit 0. Working tree byte-restauré (`git checkout --`, **JAMAIS**
|
|||||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; le seed réel
|
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; le seed réel
|
||||||
du rôle + le câblage Compupar restent côté VPS).
|
du rôle + le câblage Compupar restent côté VPS).
|
||||||
- **Auto-score 4Big** : 96/100.
|
- **Auto-score 4Big** : 96/100.
|
||||||
|
|
||||||
|
## Session `20260801_033217` · Buffer S8 · Domaine Fiches agents/colonne « Job CI » : chaque table de livrables de `03_agents/*/AGENT.md` porte une colonne **Job CI** qui NOMME entre backticks le job Gitea Actions exécutant la suite du module (`rbac-tests`, `fiscal-ecf-tests`, `frontend-portails-tests`…). Ce nom est **saisi à la main** ; la source de vérité est la clé `jobs:` de `.gitea/workflows/ci.yml`. Ce lien n'était couvert par **AUCUN gate** : `check_ci_integrity.sh` prouve que chaque job est CÂBLÉ dans `gate.needs` (INV-A/B) et les blocs amont de `check_readme_claims` recomputent les **comptes** de tests par suite — mais RIEN ne vérifiait que le nom ÉCRIT dans la fiche DÉSIGNE un job réel.
|
||||||
|
|
||||||
|
**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 de « vert
|
||||||
|
trompeur » que les cellules « Tests » par suite ou la colonne « Type » des Role
|
||||||
|
Profile — appliqué à la **surface data-derived distincte** : le NOM de job cité par
|
||||||
|
la fiche, jamais confronté à la définition réelle du workflow CI.
|
||||||
|
|
||||||
|
**Dérive silencieuse fermée** :
|
||||||
|
- `03_agents/*/AGENT.md` — colonne « Job CI » : 33 tokens `*-tests` répartis sur
|
||||||
|
13 fiches, chacun un nom de job Gitea Actions recopié à la main.
|
||||||
|
- Source faisant autorité : la section `jobs:` de `.gitea/workflows/ci.yml`.
|
||||||
|
- Piège : renommer un job dans ci.yml (`rbac-tests`→`rbac-role-tests`) ou mal
|
||||||
|
recopier `demo-scenario-tests` en `demo-scenarios-tests` laisse la fiche pointer
|
||||||
|
un job **fantôme** — le CI reste **vert** (le vrai job tourne sous son nouveau
|
||||||
|
nom), la doc d'identité de l'agent ment en silence. `check_ci_integrity` ne
|
||||||
|
regarde QUE le câblage `gate.needs`, aveugle au NOM cité par la prose.
|
||||||
|
|
||||||
|
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Fiches agents · colonne
|
||||||
|
Job CI ») : on RECOMPUTE l'ensemble des jobs depuis la clé `jobs:` de ci.yml
|
||||||
|
(la section `on:` — push/pull_request/workflow_dispatch — est AVANT `jobs:` et donc
|
||||||
|
naturellement exclue ; jamais une liste à la main) et on exige que chaque token
|
||||||
|
`*-tests` cité dans une fiche y figure. Direction **fiche→ci.yml** (le
|
||||||
|
consommateur) : ci.yml peut définir des jobs non cités (légitime), mais une fiche
|
||||||
|
ne peut pas citer un job absent. La disparition totale de la colonne échoue AUSSI
|
||||||
|
(le recensement qui s'évapore est lui-même une régression).
|
||||||
|
|
||||||
|
**Morsures vérifiées (2)** : (1) token de fiche `seo-tests`→`seo-suite-tests`
|
||||||
|
(job fantôme, mord les 2 citations dans `seo/AGENT.md`) ; (2) job ci.yml
|
||||||
|
`rbac-tests` renommé `rbac-role-tests` → mord **SIMULTANÉMENT les 4 fiches** qui
|
||||||
|
le citent (`erpnext_backend`/`ifc_speckle`/`mobile`/`rendu`). État courant :
|
||||||
|
**33 références == jobs ci.yml**, exit 0. Working tree byte-restauré
|
||||||
|
(`cp` depuis backup + `git checkout` implicite — **JAMAIS** `git clean`, interdit
|
||||||
|
absolu). Sibling gates re-verts : `check_ci_integrity`/`check_docs`/
|
||||||
|
`guard_constraints`/`check_artifacts` = PASS.
|
||||||
|
|
||||||
|
- `ci/README.md` (table récap du pipeline + paragraphe détaillé « Colonne Job CI
|
||||||
|
des fiches agents == section `jobs:` de ci.yml ») 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 ; aucun
|
||||||
|
déclenchement de workflow CI réel — analyse statique du YAML uniquement).
|
||||||
|
- **Auto-score 4Big** : 96/100.
|
||||||
|
|||||||
+22
-1
File diff suppressed because one or more lines are too long
@@ -3702,6 +3702,77 @@ if b4 is not None:
|
|||||||
+ (f" · absents={miss}" if miss else "")
|
+ (f" · absents={miss}" if miss else "")
|
||||||
+ (f" · en trop={extra}" if extra else "") + " → aligner le test")
|
+ (f" · en trop={extra}" if extra else "") + " → aligner le test")
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Fiches agents · colonne « Job CI » — chaque nom de job cité DOIT exister dans
|
||||||
|
# .gitea/workflows/ci.yml (même classe de « vert trompeur », côté câblage CI).
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Chaque table de livrables des fiches 03_agents/*/AGENT.md porte une colonne
|
||||||
|
# « Job CI » qui NOMME, mot pour mot et entre backticks, le job Gitea Actions qui
|
||||||
|
# exécute la suite du module (`rbac-tests`, `fiscal-ecf-tests`, …). Ce nom est
|
||||||
|
# SAISI À LA MAIN. La source de vérité est la section `jobs:` de ci.yml. Les
|
||||||
|
# gates existants ne couvraient PAS ce lien : `check_ci_integrity.sh` prouve que
|
||||||
|
# chaque job de ci.yml est bien CÂBLÉ dans `gate.needs` (INV-A/B), et les blocs
|
||||||
|
# amont recomputent les COMPTES de tests par suite — mais RIEN ne vérifiait que
|
||||||
|
# le nom écrit dans la fiche DÉSIGNE un job réel. Renommer un job dans ci.yml
|
||||||
|
# (ex. `rbac-tests` → `rbac-role-tests`, ou `demo-scenario-tests` mal recopié en
|
||||||
|
# `demo-scenarios-tests`) laisse la fiche pointer un job FANTÔME : le CI reste
|
||||||
|
# vert (le vrai job tourne sous son nouveau nom), la doc d'identité de l'agent
|
||||||
|
# ment en silence. On RECOMPUTE ici l'ensemble des jobs depuis la section `jobs:`
|
||||||
|
# de ci.yml (jamais une liste à la main) et on exige que chaque token `*-tests`
|
||||||
|
# cité dans une fiche y figure. Direction fiche→ci.yml (le consommateur) : ci.yml
|
||||||
|
# peut définir des jobs non cités (légitime), mais une fiche ne peut pas citer un
|
||||||
|
# job absent.
|
||||||
|
# ============================================================================
|
||||||
|
CI_YML = ".gitea/workflows/ci.yml"
|
||||||
|
try:
|
||||||
|
ci_lines = open(CI_YML, encoding="utf-8").read().splitlines()
|
||||||
|
except OSError as e:
|
||||||
|
bad(f"Job CI fiches · {CI_YML} illisible : {e}")
|
||||||
|
ci_lines = None
|
||||||
|
|
||||||
|
if ci_lines is not None:
|
||||||
|
# Ensemble des jobs = clés à 2 espaces sous la clé top-level `jobs:`
|
||||||
|
# (la section `on:` — push/pull_request/workflow_dispatch — est AVANT `jobs:`
|
||||||
|
# et donc naturellement exclue). Une clé top-level `^\S` clôt la section.
|
||||||
|
jobs = set()
|
||||||
|
in_jobs = False
|
||||||
|
for line in ci_lines:
|
||||||
|
if re.match(r"^jobs:\s*$", line):
|
||||||
|
in_jobs = True
|
||||||
|
continue
|
||||||
|
if in_jobs and re.match(r"^\S", line): # nouvelle clé top-level
|
||||||
|
break
|
||||||
|
if in_jobs:
|
||||||
|
mj = re.match(r"^ ([A-Za-z0-9_-]+):\s*$", line)
|
||||||
|
if mj:
|
||||||
|
jobs.add(mj.group(1))
|
||||||
|
if not jobs:
|
||||||
|
bad(f"Job CI fiches · aucun job détecté dans la section `jobs:` de "
|
||||||
|
f"{CI_YML} — parse cassé ou fichier vidé (régression de câblage).")
|
||||||
|
|
||||||
|
fiches_ci = subprocess.run(
|
||||||
|
["git", "ls-files", "03_agents/*/AGENT.md"],
|
||||||
|
capture_output=True, text=True).stdout.split()
|
||||||
|
tok_re = re.compile(r"`([a-z0-9]+(?:-[a-z0-9]+)*-tests)`")
|
||||||
|
seen_jobrefs = 0
|
||||||
|
for af in fiches_ci:
|
||||||
|
try:
|
||||||
|
flines = open(af, encoding="utf-8").read().splitlines()
|
||||||
|
except OSError as e:
|
||||||
|
bad(f"Job CI fiches · {af} illisible : {e}"); continue
|
||||||
|
for ln, line in enumerate(flines, 1):
|
||||||
|
for tok in tok_re.findall(line):
|
||||||
|
seen_jobrefs += 1
|
||||||
|
if jobs and tok in jobs:
|
||||||
|
good(f"Job CI · {af}:{ln} · `{tok}` == job ci.yml")
|
||||||
|
elif jobs:
|
||||||
|
bad(f"Job CI · {af}:{ln} · `{tok}` ABSENT de la section "
|
||||||
|
f"`jobs:` de {CI_YML} → job renommé/supprimé, fiche "
|
||||||
|
f"pointe un job fantôme (régénérer la fiche ou ci.yml)")
|
||||||
|
if seen_jobrefs == 0:
|
||||||
|
bad("Job CI fiches · AUCUN token `*-tests` trouvé dans les fiches — la "
|
||||||
|
"disparition de la colonne « Job CI » est elle-même une régression.")
|
||||||
|
|
||||||
sys.exit(1 if FAIL else 0)
|
sys.exit(1 if FAIL else 0)
|
||||||
PY
|
PY
|
||||||
rc=$?
|
rc=$?
|
||||||
|
|||||||
Reference in New Issue
Block a user