[DTP-Worker 20260802_060518] Sprint 8 · buffer · Traçabilité : ancrage de la CITATION roadmap_ref VERBATIM (l.N + libellé) des 4 MANIFESTs sur la ligne réelle de la roadmap
Gate anti-dérive #6 : demo/scenarios · frontend/chat_otoia · frontend/portails · mobile/app_config publient un roadmap_ref « …l.A[-B] « <bullet> » » dans out/MANIFEST.json (byte-gaté). check_artifacts ne prouve QUE spec==MANIFEST ; INV11 n'ancre que les roadmap_line NUMÉRIQUES de qa/acceptance. Reformuler/ renuméroter la roadmap laissait les 4 citations périmées en silence (silent-green prouvé : reword l.63 ⇒ 6 gates verts, chat_otoia cite toujours l'ancien texte). check_readme_claims : découvre chaque MANIFEST à citation et exige (1) fichier == roadmap canonique, (2) libellé normalisé ⊆ lignes A..B réelles, (3) spec == MANIFEST ; 4 modules connus EXIGÉS présents (anti-évaporation). 5 checks verts · 7 morsures (M1 silent-green reword roadmap · M2 renumber · M3 drift citation · M4 wrong file · M5 spec≠manifest · M6 évaporation · M7 hors-plage). Suite complète exit 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,53 @@
|
|||||||
# Activity log · 2026-08-02 · Claude Code DTP Worker
|
# Activity log · 2026-08-02 · Claude Code DTP Worker
|
||||||
|
|
||||||
|
## Sprint 8 · buffer · Traçabilité roadmap — ancrage de la CITATION `roadmap_ref` VERBATIM (n° ligne + libellé) des artefacts sur la ligne RÉELLE de la roadmap
|
||||||
|
|
||||||
|
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention · toujours
|
||||||
|
vérifier sources archives »). Le pattern « citation vérifiée, pas déclarée » (INV11
|
||||||
|
de `qa/acceptance` ancre les `roadmap_line` NUMÉRIQUES de son artefact au bullet
|
||||||
|
DELIVERABLE réel) portait un angle mort : **quatre** modules — `demo/scenarios`,
|
||||||
|
`frontend/chat_otoia`, `frontend/portails`, `mobile/app_config` — publient dans leur
|
||||||
|
`out/MANIFEST.json` (byte-gaté) un champ `roadmap_ref` de forme
|
||||||
|
`« …ROADMAP… · Sprint N l.A[-B] « <libellé bullet> » »`, où le **libellé est une
|
||||||
|
transcription VERBATIM** du bullet de la roadmap à la ligne citée. Or **aucun gate**
|
||||||
|
ne vérifiait que la ligne A[-B] porte réellement ce texte : `check_artifacts` ne
|
||||||
|
prouve QUE `spec==MANIFEST` byte-for-byte (la MÊME citation recopiée des deux côtés,
|
||||||
|
jamais contredite) ; INV11 ne touche QUE les `roadmap_line` numériques de SON
|
||||||
|
artefact ; l'ancrage Expo mobile ne teste que « roadmap » + « Expo N » dans
|
||||||
|
`expo_sdk_source`, pas la citation complète.
|
||||||
|
|
||||||
|
**Le « vert trompeur »** — RÉORDONNER la roadmap (les n° de ligne glissent) ou
|
||||||
|
REFORMULER un bullet laisse ces 4 citations pointer une ligne qui dit AUTRE CHOSE :
|
||||||
|
un agent lisant le MANIFEST pour retrouver la promesse d'origine tomberait sur le
|
||||||
|
mauvais bullet. **Prouvé par mutation** : reformuler le bullet l.63 (`Chat OTOIA
|
||||||
|
embedded…`) laissait les **6 gates VERTS** pendant que `chat_otoia/out/MANIFEST.json`
|
||||||
|
citait encore « … Chat OTOIA embedded … » à l.63. Aucune suite `tests/` (FONCTIONS
|
||||||
|
de résolution, jamais l'ancre à la roadmap) ne mord.
|
||||||
|
|
||||||
|
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Traçabilité roadmap », juste
|
||||||
|
avant `sys.exit`) — DÉCOUVRE tous les `out/MANIFEST.json` (glob 1 & 2 niveaux)
|
||||||
|
portant un `roadmap_ref` citant `(l.A[-B] «…»)` et exige, par module : **(1)** le
|
||||||
|
fichier cité == la roadmap canonique ; **(2)** le libellé, NORMALISÉ (markdown
|
||||||
|
`**`/`- ` retirés · espaces compressés · NFC), est SOUS-CHAÎNE des lignes A..B
|
||||||
|
réelles (robuste à la troncature du bullet et à la plage multi-lignes `l.56-57`) ;
|
||||||
|
**(3)** le spec du module porte le MÊME `roadmap_ref` (identité spec↔artefact publié).
|
||||||
|
Bornes de ligne hors-plage attrapées (renumérotation). Les **4 modules connus** sont
|
||||||
|
EXIGÉS présents (anti-évaporation #6 : retirer un `roadmap_ref` échoue) ; tout AUTRE
|
||||||
|
MANIFEST à citation est ancré en bonus (future-proof).
|
||||||
|
|
||||||
|
**Vérif** — 5 checks verts sur l'arbre propre (4 citations ancrées + recensement
|
||||||
|
« 4 modules attendus présents »). **7 morsures** adversariales, gate lancé SEUL,
|
||||||
|
reverts par `cp` ciblé (jamais `git checkout` large — cf. incident consigné) :
|
||||||
|
**M1 SILENT-GREEN** — reformuler le bullet l.63 (AUTORITÉ), MANIFEST inchangé ⇒
|
||||||
|
libellé ABSENT (preuve que l'autorité est la ROADMAP, pas la cohérence interne de
|
||||||
|
l'artefact) · M2 renuméroter le MANIFEST `l.63→l.62` (ligne existante mais autre
|
||||||
|
bullet) ⇒ ABSENT · M3 dériver le libellé du MANIFEST lui-même ⇒ ABSENT · M4 citer
|
||||||
|
un autre fichier roadmap ⇒ fichier ≠ canonique · M5 dériver la citation du SEUL spec
|
||||||
|
⇒ spec ≠ MANIFEST (artefact incohérent) · M6 retirer `roadmap_ref` du MANIFEST ⇒
|
||||||
|
ÉVAPORÉE ['frontend/chat_otoia'] · M7 citer `l.9999` ⇒ plage hors roadmap (1..92).
|
||||||
|
Suite complète re-verte : `check_artifacts` · `check_docs` · `guard_constraints` ·
|
||||||
|
`check_ci_integrity` · `check_regression` · `check_readme_claims` tous exit 0.
|
||||||
|
|
||||||
## Sprint 8 · buffer · RBAC SPEC §6 — ancrage de l'ÉNUMÉRATION des DocTypes `custom` sur le catalogue du contrat (2ᵉ surface prose)
|
## Sprint 8 · buffer · RBAC SPEC §6 — ancrage de l'ÉNUMÉRATION des DocTypes `custom` sur le catalogue du contrat (2ᵉ surface prose)
|
||||||
|
|
||||||
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention »). Le
|
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention »). Le
|
||||||
|
|||||||
@@ -8457,6 +8457,106 @@ if cmi_src is not None:
|
|||||||
bad(f"Commissions invariants · {CMI_RD} — énumération prose {cmi_enum} "
|
bad(f"Commissions invariants · {CMI_RD} — énumération prose {cmi_enum} "
|
||||||
f"≠ 1..{cmi_ninv} (item sauté/dupliqué) → régénérer le README")
|
f"≠ 1..{cmi_ninv} (item sauté/dupliqué) → régénérer le README")
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Traçabilité roadmap · le `roadmap_ref` VERBATIM des artefacts — la CITATION
|
||||||
|
# (n° de ligne + « libellé bullet ») ANCRÉE sur la ligne RÉELLE de la roadmap,
|
||||||
|
# pas seulement déclarée.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Quatre modules (demo/scenarios · frontend/chat_otoia · frontend/portails ·
|
||||||
|
# mobile/app_config) publient dans out/MANIFEST.json (byte-gaté par
|
||||||
|
# check_artifacts) un `roadmap_ref` de la forme :
|
||||||
|
# « 04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md · Sprint N l.A[-B] « <libellé bullet> » »
|
||||||
|
# Ce libellé est une TRANSCRIPTION VERBATIM du bullet de la roadmap à la ligne
|
||||||
|
# citée — mais AUCUN gate ne vérifiait que la ligne A[-B] porte RÉELLEMENT ce
|
||||||
|
# texte : check_artifacts ne prouve QUE spec==MANIFEST (byte-for-byte, la MÊME
|
||||||
|
# citation recopiée des deux côtés — l'un ne contredit jamais l'autre) ;
|
||||||
|
# l'ancrage roadmap de qa/acceptance (INV11) ne touche QUE les `roadmap_line`
|
||||||
|
# NUMÉRIQUES de SON artefact, jamais le libellé cité par les autres specs ;
|
||||||
|
# l'ancrage Expo (mobile) ne vérifie que la présence de « roadmap » + « Expo N »
|
||||||
|
# dans `expo_sdk_source`, pas la citation complète. → REORDONNER la roadmap (les
|
||||||
|
# n° de ligne glissent) ou REFORMULER un bullet laisse ces 4 citations pointer
|
||||||
|
# une ligne qui dit AUTRE CHOSE : « vert trompeur » de traçabilité (#6)
|
||||||
|
# qu'aucune suite tests/ (FONCTIONS de résolution, jamais l'ancre) n'attrape.
|
||||||
|
# Prouvé par mutation : reformuler le bullet l.63 laissait les 6 gates VERTS
|
||||||
|
# pendant que chat_otoia citait encore « … Chat OTOIA embedded … » à l.63.
|
||||||
|
# On ANCRE : pour chaque MANIFEST portant un `roadmap_ref` citant (l.A[-B] «…»),
|
||||||
|
# (1) le fichier cité == la roadmap canonique ; (2) le libellé, NORMALISÉ
|
||||||
|
# (markdown `**`/`- ` retirés, espaces compressés, NFC), est SOUS-CHAÎNE des
|
||||||
|
# lignes A..B réelles ; (3) le spec du module porte le MÊME `roadmap_ref`
|
||||||
|
# (identité spec↔artefact publié). Les 4 modules connus sont EXIGÉS présents
|
||||||
|
# (anti-évaporation #6) ; tout AUTRE MANIFEST à citation est ancré en bonus.
|
||||||
|
# ============================================================================
|
||||||
|
import glob as _glob
|
||||||
|
ROADMAP_REL = "04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md"
|
||||||
|
RMREF_EXPECTED = {"demo/scenarios", "frontend/chat_otoia",
|
||||||
|
"frontend/portails", "mobile/app_config"}
|
||||||
|
def _rmn(s): # normalise une ligne markdown pour comparaison de libellé
|
||||||
|
s = unicodedata.normalize("NFC", str(s))
|
||||||
|
s = re.sub(r"^\s*[-*+]\s+", "", s) # marqueur de liste en tête de ligne
|
||||||
|
s = s.replace("*", "") # emphase **gras** / *ital*
|
||||||
|
return re.sub(r"\s+", " ", s).strip()
|
||||||
|
try:
|
||||||
|
_rm_lines = open(ROADMAP_REL, encoding="utf-8").read().splitlines()
|
||||||
|
except OSError as e:
|
||||||
|
bad(f"Traçabilité roadmap · {ROADMAP_REL} illisible : {e}"); _rm_lines = None
|
||||||
|
if _rm_lines is not None:
|
||||||
|
_man_paths = sorted(set(_glob.glob(f"{D}/*/*/out/MANIFEST.json") +
|
||||||
|
_glob.glob(f"{D}/*/out/MANIFEST.json")))
|
||||||
|
_rm_seen = set()
|
||||||
|
for _mp in _man_paths:
|
||||||
|
_mod = _mp[len(D) + 1:].rsplit("/out/", 1)[0] # ex. « demo/scenarios »
|
||||||
|
try:
|
||||||
|
_ref = json.load(open(_mp, encoding="utf-8")).get("roadmap_ref", "") or ""
|
||||||
|
except (OSError, ValueError) as e:
|
||||||
|
bad(f"Traçabilité roadmap · {_mp} illisible : {e}"); continue
|
||||||
|
_mln = re.search(r"l\.(\d+)(?:-(\d+))?", _ref)
|
||||||
|
_mq = re.search(r"«\s*(.+?)\s*»", _ref)
|
||||||
|
if not (_mln and _mq):
|
||||||
|
continue # pas une citation ligne+libellé → hors périmètre de ce gate
|
||||||
|
_rm_seen.add(_mod)
|
||||||
|
_path = _ref.split(" · ", 1)[0].strip()
|
||||||
|
_a = int(_mln.group(1)); _b = int(_mln.group(2) or _mln.group(1))
|
||||||
|
_quote = _mq.group(1)
|
||||||
|
# (1) fichier cité == roadmap canonique
|
||||||
|
if _path != ROADMAP_REL:
|
||||||
|
bad(f"Traçabilité roadmap · {_mod} — cite « {_path} » ≠ roadmap "
|
||||||
|
f"canonique « {ROADMAP_REL} »"); continue
|
||||||
|
# bornes de ligne valides (renumérotation hors-plage attrapée ici)
|
||||||
|
if not (1 <= _a <= _b <= len(_rm_lines)):
|
||||||
|
bad(f"Traçabilité roadmap · {_mod} — plage l.{_a}-{_b} hors roadmap "
|
||||||
|
f"(1..{len(_rm_lines)})"); continue
|
||||||
|
_hay = " ".join(_rmn(_rm_lines[_i - 1]) for _i in range(_a, _b + 1))
|
||||||
|
_rng = f"l.{_a}" + ("" if _a == _b else f"-{_b}")
|
||||||
|
# (2) libellé cité == sous-chaîne des lignes réelles A..B
|
||||||
|
if _rmn(_quote) not in _hay:
|
||||||
|
bad(f"Traçabilité roadmap · {_mod} — libellé cité « {_quote} » ABSENT "
|
||||||
|
f"des lignes {_rng} de la roadmap (qui disent « {_hay} ») → "
|
||||||
|
f"REFORMULATION/RENUMÉROTATION : aligner le roadmap_ref (ou la roadmap)")
|
||||||
|
continue
|
||||||
|
# (3) spec du module porte le MÊME roadmap_ref (identité spec↔artefact publié)
|
||||||
|
_specs = _glob.glob(f"{D}/{_mod}/*_spec.json")
|
||||||
|
_spec_ok = True
|
||||||
|
if len(_specs) == 1:
|
||||||
|
try:
|
||||||
|
_sref = json.load(open(_specs[0], encoding="utf-8")).get("roadmap_ref")
|
||||||
|
except (OSError, ValueError):
|
||||||
|
_sref = None
|
||||||
|
if _sref is not None and _sref != _ref:
|
||||||
|
_spec_ok = False
|
||||||
|
bad(f"Traçabilité roadmap · {_mod} — spec roadmap_ref « {_sref} » ≠ "
|
||||||
|
f"MANIFEST « {_ref} » (artefact interne incohérent)")
|
||||||
|
if _spec_ok:
|
||||||
|
good(f"Traçabilité roadmap · {_mod} — citation {_rng} « {_quote} » "
|
||||||
|
f"== roadmap")
|
||||||
|
# anti-évaporation : les 4 citations connues doivent TOUTES subsister
|
||||||
|
_rm_missing = sorted(RMREF_EXPECTED - _rm_seen)
|
||||||
|
if _rm_missing:
|
||||||
|
bad(f"Traçabilité roadmap · citation roadmap_ref ÉVAPORÉE pour {_rm_missing} "
|
||||||
|
f"(module attendu sans (l.N «…») dans out/MANIFEST.json · #6)")
|
||||||
|
elif _rm_seen:
|
||||||
|
good(f"Traçabilité roadmap · {len(_rm_seen)} citation(s) ancrée(s), "
|
||||||
|
f"4 modules attendus présents")
|
||||||
|
|
||||||
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