Files
flowdeck/tests/test_fusion_format_commun.py
T
Spark 913d6137b1
FlowDeck CI / lint (push) Successful in 1m51s
FlowDeck CI / docker (push) Blocked by required conditions
FlowDeck CI / test (push) In progress
feat(fusion): format commun des skills (ACC-4.5), pilote réunion → ObsiGate (ACC-6.2), contrat panneau (ACC-4.4) — 7.84.0
2026-10-26 16:19:16 -04:00

79 lines
3.3 KiB
Python

"""Fusion ACC-4.5 — conversion d'Agents & Skills Flowdeck au format
commun (contrat ACC-0.3, `dracodev-commons/contrats/skill-format.md`).
Preuve du format : trois presets de la galerie Flowdeck convertis en
`skills-communs/<nom>/SKILL.md` (compte-rendu-reunion, rapport-hebdo,
resume-document). Ils doivent être conformes au contrat, se convertir
en champs Flowdeck et s'installer dans un workspace via le chemin
existant (`skill_gallery.upsert_skill`).
"""
from pathlib import Path
import pytest
from app.services import skill_format, skill_gallery
RACINE = Path(__file__).resolve().parent.parent
CONVERTIS = ["compte-rendu-reunion", "rapport-hebdo", "resume-document"]
def _lire(nom: str) -> str:
return (RACINE / "skills-communs" / nom / "SKILL.md").read_text(encoding="utf-8")
def test_trois_skills_convertis_conformes():
for nom in CONVERTIS:
skill = skill_format.analyser_skill_md(_lire(nom))
assert skill_format.valider(skill) == [], (nom, skill_format.valider(skill))
assert skill["meta"]["name"] == nom
assert skill["meta"]["apps"] == ["flowdeck"]
assert skill["meta"]["version"] == "1.0.0"
# Toute écriture est déclarée, avec approbation explicite.
actions = {e["action"] for e in skill["meta"]["ecritures"]}
assert actions == {"flowdeck.create_document", "flowdeck.write_blocks"}
def test_conversion_vers_flowdeck_et_installation(client):
for nom in CONVERTIS:
skill = skill_format.analyser_skill_md(_lire(nom))
champs = skill_format.vers_champs_flowdeck(skill)
assert champs["name"] == nom
assert set(champs["allowed_tools"]) == {
"search_workspace", "read_document", "create_document", "write_blocks"}
assert "Procédure" in champs["prompt_template"]
assert "Garde-fous" in champs["prompt_template"]
row, cree = skill_gallery.upsert_skill(
champs, workspace_id=None, created_by=1)
assert cree is True and row["name"] == nom
def test_validation_rejette_les_ecarts():
incomplet = skill_format.analyser_skill_md(
"---\nname: mauvais nom\napps: [flowdeck]\n---\n\n## Procédure\n\nx\n")
erreurs = skill_format.valider(incomplet)
assert any("kebab" in e for e in erreurs)
assert any("description" in e for e in erreurs)
assert any("Quand l'utiliser" in e for e in erreurs)
with pytest.raises(ValueError):
skill_format.vers_champs_flowdeck(incomplet)
def test_ecritures_obligatoires_si_outil_ecrivant():
texte = (
"---\nname: supprime-tout\ndescription: x\nversion: 1.0.0\n"
"apps: [flowdeck]\ndomaines: [pro]\noutils: [flowdeck.delete_page]\n---\n\n"
"## Quand l'utiliser\n\nx\n\n## Procédure\n\nx\n\n## Garde-fous\n\nx\n")
erreurs = skill_format.valider(skill_format.analyser_skill_md(texte))
assert any("ecritures obligatoire" in e for e in erreurs)
def test_aller_retour_depuis_un_preset():
preset = skill_gallery.get_gallery("compte-rendu-reunion")
texte = skill_format.depuis_preset_flowdeck(preset, domaines=["pro"])
skill = skill_format.analyser_skill_md(texte)
assert skill_format.valider(skill) == []
champs = skill_format.vers_champs_flowdeck(skill)
assert champs["name"] == "compte-rendu-de-reunion"
assert "create_document" in champs["allowed_tools"]