02.03.06 — drive_page#
Fichier source :
src/ocarina/opinionated/dsl/drive_page.py
Code#
def drive_page(
first: ActionSuccess[TPOM], *rest: ActionSuccess[TPOM]
) -> ChainRunner[TPOM]:
return chain_actions(first, *rest)C’est exactement chain_actions.
Pourquoi cet alias ?#
1. Sémantique : « je prends le contrôle d’une page »#
Citation du Holy Book (Premiers scénarios) :
drive_pageexprime que l’on prend le contrôle d’une page. Toute transition devient explicite par l’ouverture d’un nouveaudrive_page.
return [
drive_page(
act(on_homepage, open_homepage)...,
act(on_homepage, verify_homepage)...,
act(on_homepage, click_cta)...,
), # ⬅ fermeture du contrôle de la homepage
drive_page( # ⬅ ouverture du contrôle de la page suivante
act(on_target_page, verify_target_page)...,
),
]2. Discipline#
Mélanger des actes sur deux POMs différents dans un même drive_page devient une erreur mypy (cf. 02-action-chain-states.md, section « narrowing par act() »). Cela force concrètement à respecter la sémantique.
3. Lecture des rapports#
Le CLAUDE.md d’ocarina-with-ai-example documente la règle qui dépend de cette sémantique :
Every
drive_pageproduces at least onelog_and_screenshot. Adrive_pagemodels one page’s worth of work and almost always ends by submitting / navigating / verifying — it is a page transition. The report’s screenshot sequence must let a reader replay the journeydrive_pagebydrive_page; « one screenshot per scenario » collapses a multi-page journey into a single still.
Donc : un drive_page = un screenshot de fin (au moins). Le rapport DOCX (cf. ../11-opinionated/05-plugins-reports.md) devient une bande dessinée du parcours.
Conséquences architecturales#
| Conséquence | Détail |
|---|---|
Un drive_page est typé sur un POM (ChainRunner[TPOM]) | Le checker refuse les pas de test sur des pages hétérogènes |
Multi-pages = liste de drive_page | Le scénario retourne list[drive_page(...), drive_page(...), drive_page(...)] |
| Composabilité | drive_page(...) est un ChainRunner ; on peut le stocker dans une variable, le passer en argument, le mettre dans une branche match_page |
| Pas de logique custom | drive_page est un monomorphisme de chain_actions (même fonction, type plus étroit). On peut écrire son propre drive_component ou drive_modal qui retourne aussi un ChainRunner et qui se compose avec |
L’alias est dans opinionated/, pas dans dsl/#
drive_page vit dans src/ocarina/opinionated/dsl/, pas dans src/ocarina/dsl/.
- Le DSL « pur » ne contient que
chain_actions(etcreate_act,match_page). drive_pageest un alias sémantique opt-in, un monomorphisme dechain_actionsqui n’apporte aucune logique mais nomme l’intention.- Un projet pourrait théoriquement importer uniquement
chain_actionset créer son propre alias (drive_workflow,drive_section,drive_component, etc.) sans toucher au framework.
C’est cohérent avec la philosophie « grammaire souveraine » du Holy Book. Voir ../../11-independence/01-sovereign-grammar.md
Tests dédiés#
Plusieurs tests dans tests/scenarios/ exercent drive_page (via les conftest acting(pom, step) et scenario_of("ok")). Ces tests valident :
- l’exécution séquentielle des actes,
- le court-circuit après échec,
- le comptage d’
actthread-local.