[DTP-Worker] Sprint 7/8 · Livrable démo : prompteur Markdown (out/run_sheet.md)
Le seul livrable démo (demo/scenarios) ne produisait qu'un run-sheet JSON machine — aucun support lisible par un présentateur, alors que le Sprint 7 vise un scénario « prêt à jouer ». Rendu Markdown in-repo depuis le JSON = même pattern que faisabilite (rend des .md), zéro écriture VPS. - scenlib/render.py : render_markdown() PUR/déterministe, ne lit que le run-sheet (déjà anti-inventé), aucun chiffre nouveau (#6). - build émet out/run_sheet.md (prompteur : par beat, table « À dire | Chiffre | Source (preuve) » traçant le pointeur RFC 6901 amont). - Compat vérifiée : HANDOFF 4Big ne json.load que les .json (ignore .md) ; check_artifacts diffe tout fichier build → md commité + reproductible. - Consommateurs régénérés : régression 551→558 (22 suites PASS) ; quality_report.json (README 5011→5575 o · 32→39 test_*) PASS 22/22 ; 03_agents/qa/AGENT.md 551→558 ; README démo auto-score 96→97. - 7 gates verts · 39 tests démo · 34 tests audit · arbre propre. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@ _MOD = os.path.normpath(os.path.join(_HERE, ".."))
|
||||
sys.path.insert(0, _MOD)
|
||||
|
||||
import demo_scenario_gen as gen # noqa: E402
|
||||
from scenlib import builder, evidence # noqa: E402
|
||||
from scenlib import builder, evidence, render # noqa: E402
|
||||
|
||||
|
||||
def _fresh():
|
||||
@@ -214,6 +214,51 @@ class TestInjectionsNegatives(unittest.TestCase):
|
||||
self.assertTrue(gen.deps.validate(mf, gen._load_schema()))
|
||||
|
||||
|
||||
class TestRenderMarkdown(unittest.TestCase):
|
||||
"""Le prompteur Markdown : déterministe et sans donnée nouvelle (#6)."""
|
||||
|
||||
def setUp(self):
|
||||
_, self.run_sheet, _ = _fresh()
|
||||
self.md = render.render_markdown(self.run_sheet)
|
||||
|
||||
def test_deterministe(self):
|
||||
self.assertEqual(self.md, render.render_markdown(self.run_sheet))
|
||||
|
||||
def test_termine_par_un_saut_de_ligne(self):
|
||||
self.assertTrue(self.md.endswith("\n"))
|
||||
self.assertFalse(self.md.endswith("\n\n"))
|
||||
|
||||
def test_titres_scenarios_presents(self):
|
||||
for sc in self.run_sheet["scenarios"]:
|
||||
self.assertIn(sc["titre"], self.md)
|
||||
self.assertIn(sc["id"], self.md)
|
||||
|
||||
def test_chaque_beat_rendu(self):
|
||||
for sc in self.run_sheet["scenarios"]:
|
||||
for b in sc["beats"]:
|
||||
self.assertIn(b["titre"], self.md)
|
||||
self.assertIn(b["role_narratif"], self.md)
|
||||
|
||||
def test_valeurs_proviennent_du_run_sheet(self):
|
||||
# Anti-invention : chaque valeur affichée est celle, formatée, d'une
|
||||
# citation — jamais un chiffre nouveau. On vérifie la présence verbatim.
|
||||
for sc in self.run_sheet["scenarios"]:
|
||||
for b in sc["beats"]:
|
||||
for c in b["evidence"]:
|
||||
self.assertIn(render._fmt(c["valeur"]), self.md)
|
||||
|
||||
def test_fmt_bool_liste_none(self):
|
||||
self.assertEqual(render._fmt(True), "oui")
|
||||
self.assertEqual(render._fmt(False), "non")
|
||||
self.assertEqual(render._fmt(["fr", "en"]), "fr, en")
|
||||
self.assertEqual(render._fmt(50), "50")
|
||||
self.assertEqual(render._fmt(None), "`—`")
|
||||
|
||||
def test_placeholder_non_promu_en_chiffre(self):
|
||||
# Un placeholder survivant est rendu entre back-ticks, jamais nu.
|
||||
self.assertEqual(render._fmt("{{m:f#/p}}"), "`{{m:f#/p}}`")
|
||||
|
||||
|
||||
class TestCLI(unittest.TestCase):
|
||||
def test_validate_retourne_zero(self):
|
||||
self.assertEqual(gen.main(["validate"]), 0)
|
||||
@@ -222,7 +267,7 @@ class TestCLI(unittest.TestCase):
|
||||
import tempfile
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
self.assertEqual(gen.main(["build", "-o", d]), 0)
|
||||
for name in ("run_sheet.json", "MANIFEST.json"):
|
||||
for name in ("run_sheet.json", "MANIFEST.json", "run_sheet.md"):
|
||||
self.assertTrue(os.path.isfile(os.path.join(d, name)))
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user