[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
|
||||
du rôle + le câblage Compupar restent côté VPS).
|
||||
- **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" · 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)
|
||||
PY
|
||||
rc=$?
|
||||
|
||||
Reference in New Issue
Block a user