[DTP-Worker] Sprint 8 · buffer · DevOps/deploy_runbook : IMPUTABILITÉ des CONFIRMATIONS préalables VPS (owner · réf-contrôle) ancrée sur out/deploy_runbook.json ⨯ qa/audit_5d

La ligne « Confirmations préalables VPS » du README `devops/deploy_runbook` annote
CHAQUE confirmation réglementaire d'un COUPLE data-derived `nom` (OWNER · RÉF-CONTRÔLE)
— ex. `taux_commission` (Direction · audit_5d D1.1) : QUI doit confirmer le paramètre
avant déploiement + QUEL contrôle qa/audit_5d le trace. Sources faisant autorité
(double, byte-gatées) : les `confirmations` de out/deploy_runbook.json (owner + source)
CROISÉES avec qa/audit_5d/out/audit_report.json (chaque control D#.# porte son propre
owner). Les blocs DevOps amont ne gataient que le COMPTE (2) et l'ENSEMBLE des noms —
AVEUGLES à QUI porte chaque confirmation et à QUEL contrôle la trace. Piège #6 :
réaffecter `taux_commission` de Direction à Ventes (mauvais responsable escaladé),
misattribuer le contrôle (D1.1→D2.1) ou citer un contrôle FANTÔME (D9.9) laisse la
prose périmée en silence pendant que l'artefact/l'audit disent autre chose → l'agent
DevOps escaladerait le mauvais owner / contrôle ; aucune suite tests/ (FONCTIONS de
graphe) n'attrape ce « vert trompeur ». État courant : aucune annotation périmée
(anti-invention #6), le défaut est la surface ungated.

Gate ajouté (ci/check_readme_claims.sh, bloc « 2ter ») : cross-anchor à trois — owner
run-book ⊆ owner du contrôle audit_5d cité (tolère le suffixe « / UAF ») · owner
README ⊆ owner run-book (tolère l'abréviation « Fiscaliste eCF » ⊂ « Compta Fiscaliste
eCF ») · réf README == contrôle réel présent DANS audit_5d ET dans la source. Une
confirmation tracée DOIT rester annotée (traçabilité #6) ; une annotation d'un nom
fantôme échoue AUSSI.

9 morsures vérifiées (README réaffecte owner · misattribue D1.1→D2.1 · contrôle
fantôme D9.9 · annotation retirée · artefact réaffecte owner = silent green · audit_5d
owner divergent · source cite contrôle fantôme · annotation nom fantôme · réf textuelle
absente de la source), restauré vert, 7 gates re-verts. ci/README.md (récap + paragraphe
« 3ᵉ surface deploy_runbook — imputabilité des confirmations ») mis à jour.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code DTP Worker
2026-08-01 08:41:43 +00:00
parent 9353d7f54e
commit 51e447605f
3 changed files with 210 additions and 1 deletions
+114
View File
@@ -1803,6 +1803,120 @@ if dr_plan is not None:
bad(f"DevOps · phase {o} — {DR_RD} « Dépend de » = {got_deps or '—'} MAIS "
f"artefact dit {deps or '—'} → régénérer le README")
# 2ter) deploy_runbook — IMPUTABILITÉ des CONFIRMATIONS préalables VPS ------------
# La ligne « Confirmations préalables VPS » du README annote CHAQUE confirmation
# réglementaire d'un COUPLE data-derived : `nom` (OWNER · RÉF-CONTRÔLE), ex.
# `taux_commission` (Direction · audit_5d D1.1). L'OWNER = QUI doit confirmer le
# paramètre avant déploiement ; la RÉF = le contrôle qa/audit_5d (`D#.#`) — ou la
# session — qui en assure le suivi. Source faisant autorité : les `confirmations`
# de out/deploy_runbook.json (byte-gaté) — chaque item porte `owner` + `source` —
# CROISÉES avec le rapport qa/audit_5d (byte-gaté) : le contrôle cité y porte SON
# PROPRE `owner`. Les blocs DevOps amont ne gatent que le COMPTE de confirmations
# (2) et l'ENSEMBLE de leurs noms (bloc énumération) — AVEUGLES à QUI porte chaque
# confirmation et à QUEL contrôle la trace. Piège #6 : RÉAFFECTER `taux_commission`
# de Direction à Ventes (mauvais responsable relancé → confirmation jamais obtenue),
# MISATTRIBUER le contrôle (`D1.1`→`D2.1`, pointant un contrôle qui ne trace PAS ce
# paramètre) ou citer un contrôle FANTÔME (`D9.9`, absent d'audit_5d) laisse la
# prose périmée EN SILENCE pendant que l'artefact/l'audit disent autre chose →
# l'agent DevOps escaladerait le mauvais owner / le mauvais contrôle. La table
# phases (2bis) est aveugle aux confirmations ; aucune suite tests/ (FONCTIONS de
# graphe) n'attrape la prose. Cross-anchor à 3 : owner runbook COMPATIBLE avec
# owner du contrôle audit_5d (sous-ensemble de tokens · tolère le suffixe éditorial
# « / UAF ») · owner README ⊆ owner runbook (tolère l'abréviation « Fiscaliste eCF »
# ⊂ « Compta Fiscaliste eCF ») · réf README == contrôle réel (présent dans audit_5d
# ET dans la source). Une confirmation tracée par un contrôle DOIT rester annotée
# (disparition = régression de traçabilité #6). Une annotation d'un nom FANTÔME
# échoue AUSSI.
try:
a5_rep = load("qa/audit_5d/out/audit_report.json")
a5_owner = {c["id"]: c["owner"] for c in a5_rep["controls"]}
except (OSError, KeyError, ValueError) as e:
bad(f"DevOps · confirmations — rapport audit_5d illisible : {e}"); a5_owner = None
dr_rd2 = read_norm(DR_RD)
if dr_plan is not None and a5_owner is not None and dr_rd2 is not None:
def _toks(s):
return {t for t in re.split(r"\s+", s.strip()) if t}
def _ctrl(s):
m = re.search(r"D\d\.\d+", s)
return m.group(0) if m else None
# confirmations aplaties (id → item) + unicité inter-phases
conf_by_id, dups = {}, []
for p in dr_plan:
for c in p.get("confirmations", []):
if c["id"] in conf_by_id:
dups.append(c["id"])
conf_by_id[c["id"]] = c
if dups:
bad(f"DevOps · confirmations — id(s) DUPLIQUÉ(s) inter-phases "
f"{sorted(set(dups))} (plan incohérent)")
# tracked : confirmations dont la `source` cite un contrôle audit_5d `D#.#`
tracked = {cid: _ctrl(c["source"]) for cid, c in conf_by_id.items()}
# annotations README : `nom` (owner · réf)
ann = {}
seg = re.search(r"Confirmations préalables VPS\*\* \(consolidées, sourcées\) : "
r"(.+?) ## ", dr_rd2)
if seg is None:
bad(f"DevOps · {DR_RD} — ligne « Confirmations préalables VPS » INTROUVABLE "
f"(imputabilité non vérifiable)")
else:
for name, body in re.findall(r"`([a-z_]+)`\s*\(([^)]+)\)", seg.group(1)):
parts = [x.strip() for x in body.split("·")]
if len(parts) == 2:
ann[name] = {"owner": parts[0], "ref": parts[1]}
# (a) cross-module : chaque confirmation tracée porte un contrôle audit_5d RÉEL
# dont l'owner est COMPATIBLE avec l'owner du run-book (séparation des
# pouvoirs cohérente entre modules).
for cid, ctrl in sorted(tracked.items()):
if ctrl is None:
continue
c = conf_by_id[cid]
if ctrl not in a5_owner:
bad(f"DevOps · confirmation `{cid}` — source cite le contrôle `{ctrl}` "
f"ABSENT du rapport qa/audit_5d (contrôle FANTÔME)"); continue
if not _toks(c["owner"]) <= _toks(a5_owner[ctrl]):
bad(f"DevOps · confirmation `{cid}` — owner run-book « {c['owner']} » "
f"INCOMPATIBLE avec owner du contrôle {ctrl} audit_5d "
f"« {a5_owner[ctrl]} » (imputabilité divergente inter-modules)")
else:
good(f"DevOps · confirmation `{cid}` — owner « {c['owner']} » ⊆ owner "
f"contrôle {ctrl} audit_5d (imputabilité cohérente)")
if cid not in ann:
bad(f"DevOps · confirmation `{cid}` (tracée par {ctrl}) — annotation "
f"« (owner · réf) » INTROUVABLE dans {DR_RD} → régénérer le README")
# (b) chaque annotation README désigne une confirmation RÉELLE + owner/réf exacts
for cid, a in sorted(ann.items()):
c = conf_by_id.get(cid)
if c is None:
bad(f"DevOps · annotation README `{cid}` — confirmation FANTÔME "
f"(absente du run-book) → régénérer le README"); continue
if not _toks(a["owner"]) <= _toks(c["owner"]):
bad(f"DevOps · confirmation `{cid}` — README owner « {a['owner']} » "
f"n'est PAS un sous-ensemble de l'owner artefact « {c['owner']} » "
f"→ mauvais responsable")
else:
good(f"DevOps · confirmation `{cid}` — README owner « {a['owner']} » ⊆ "
f"artefact « {c['owner']} »")
ref_ctrl = _ctrl(a["ref"])
if ref_ctrl is not None:
# réf = contrôle audit_5d : doit == le contrôle de la source ET exister
if ref_ctrl != tracked.get(cid):
bad(f"DevOps · confirmation `{cid}` — README réf cite {ref_ctrl} MAIS "
f"la source artefact trace {tracked.get(cid) or '(aucun contrôle)'} "
f"→ contrôle audit_5d périmé")
elif ref_ctrl not in a5_owner:
bad(f"DevOps · confirmation `{cid}` — README réf cite le contrôle "
f"`{ref_ctrl}` ABSENT du rapport qa/audit_5d (fantôme)")
else:
good(f"DevOps · confirmation `{cid}` — réf README == contrôle "
f"{ref_ctrl} (présent audit_5d + source)")
else:
# réf textuelle (ex. « session 19 ») : doit apparaître dans la source
if a["ref"] not in c["source"]:
bad(f"DevOps · confirmation `{cid}` — README réf « {a['ref']} » ABSENTE "
f"de la source artefact « {c['source']} »")
else:
good(f"DevOps · confirmation `{cid}` — réf « {a['ref']} » == source artefact")
# ============================================================================
# Démo · run-sheet de pitch (nombre de modules cités) — même classe de « vert
# trompeur », transcrit À LA MAIN dans le diagramme d'architecture du README du