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_page exprime que l’on prend le contrôle d’une page. Toute transition devient explicite par l’ouverture d’un nouveau drive_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_page produces at least one log_and_screenshot. A drive_page models 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 journey drive_page by drive_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équenceDé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_pageLe 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 customdrive_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 (et create_act, match_page).
  • drive_page est un alias sémantique opt-in, un monomorphisme de chain_actions qui n’apporte aucune logique mais nomme l’intention.
  • Un projet pourrait théoriquement importer uniquement chain_actions et 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’act thread-local.