Aller au contenu principal
Version: 1.0.0

Trigger réel gouverné : revue matinale

Ce tutoriel montre comment lancer une exécution Touba automatiquement avec un trigger schedule -> strategy. Le scénario se concentre sur le déclenchement, les limites et la trace avant d’ajouter des tools réels.

Vous allez construire une revue matinale qui se déclenche après environ une seconde, affiche deux messages, retourne un titre et écrit une trace.

Ce que vous allez apprendre​

ÉtapeCe que vous vérifiez
Source .tbLe trigger déclare quand lancer une stratégie et avec quels arguments
AIRLe trigger devient un artefact runtime, pas un commentaire
ManifestL’hôte active explicitement le trigger autorisé
Runnertouba trigger run attend l’intervalle puis lance la stratégie
État durable de triggertouba.triggers.sqlite garde les event_id consommés
TraceLe runtime enregistre réception, acceptation, début et fin d’exécution
RefusUn replay ou un trigger désactivé est refusé avant exécution

1. Créer le dossier​

Terminal
mkdir -p morning-trigger-demo
cd morning-trigger-demo

Créez ensuite le fichier source.

morning-review.tb
module examples.trigger_morning_review

define ReviewTopic as Text = "signaux produit Touba"
define RiskTheme as Text = "risques agents"

function BuildReviewTitle
takes topic as Text
gives Text
do
give "Revue matinale: " ++ topic

skill BuildMorningBrief
description "Build and display the morning review for the supplied topic."
takes topic as Text
gives Text
do
BuildReviewTitle
with topic as topic
into title

show
with message as title

show
with message as "Point de controle: verifier traces, refus et prochaines actions"

give title

strategy RunMorningReview
takes topic as Text
gives Text
uses BuildMorningBrief
do
bind scoped_topic as Text = topic ++ " / " ++ RiskTheme

BuildMorningBrief
with topic as scoped_topic
into title

give title

trigger MorningReview
on schedule "every 1s"
runs strategy RunMorningReview
with topic as ReviewTopic
limits
max_runs_per_day as 1
timeout_ms as 30000

Ce fichier contient quatre idées distinctes :

  • define nomme des valeurs non sensibles au niveau du module ;
  • function construit un titre sans effet externe ;
  • skill affiche le résultat et retourne une valeur ;
  • trigger lance la stratégie selon un intervalle borné.

Le trigger utilise le standard du runner foreground :

Formats disponibles
every <n>s
every <n>m
every <n>h

Un cron complet n’est pas exécuté par le runner.

2. Compiler vers AIR​

Terminal
touba compile morning-review.tb --out morning-review.air.json

À ce stade, rien n’est exécuté. La compilation produit l’AIR : le contrat que le runtime va consommer.

Vous pouvez inspecter l’AIR :

Terminal
touba inspect morning-review.air.json

Vous devez y voir une stratégie RunMorningReview et un trigger MorningReview.

3. Activer le trigger​

Un trigger Touba n’est pas actif simplement parce qu’il existe dans le source. L’hôte doit l’autoriser dans un manifest.

Créez touba.manifest.json :

touba.manifest.json
{
"manifest_version": "touba-manifest-v1",
"triggers": {
"trigger:examples.trigger_morning_review/MorningReview": {
"enabled": true,
"source": {
"kind": "schedule"
},
"limits": {
"max_runs_per_day": 1,
"timeout_ms": 30000
}
}
}
}

Le manifest dit trois choses :

  • ce trigger est activé dans cet environnement ;
  • la source autorisée est schedule ;
  • les limites de l’hôte n’élargissent pas celles du source .tb.

4. Lancer le trigger réel​

Terminal
touba trigger run morning-review.air.json \
--manifest touba.manifest.json \
--trigger trigger:examples.trigger_morning_review/MorningReview \
--max-runs 1 \
--state touba.triggers.sqlite \
--trace-out morning-review.trace.json

La commande attend l’intervalle every 1s, génère un événement normalisé, puis lance la stratégie.

Sortie attendue :

Sortie
Revue matinale: signaux produit Touba / risques agents
Point de controle: verifier traces, refus et prochaines actions

Le runner s’arrête après un run parce que --max-runs 1 est explicite. Sans --max-runs, la CLI refuse de démarrer. Sans --state, le registre est créé dans .touba/triggers.sqlite.

--state crée ou met à jour un état durable de trigger. Cet état ne contient pas de payload brut ; il conserve seulement les event_id, les statuts acceptés/refusés, les raisons de refus et la clé de jour UTC utilisée pour appliquer max_runs_per_day. Le chemin passé à --state doit se terminer par .triggers.sqlite.

5. Lire la trace​

La trace est écrite dans morning-review.trace.json.

Terminal
touba inspect morning-review.trace.json
touba trigger state touba.triggers.sqlite --trigger trigger:examples.trigger_morning_review/MorningReview

La trace doit rendre visibles les événements suivants :

Événements attendus
trigger_event_received
trigger_event_accepted
trigger_execution_started
user_interaction_shown
trigger_execution_completed
run_completed

Ce point est important : l’affichage terminal n’est pas la seule preuve. La trace reste l’artefact d’audit du run.

L’inspection de touba.triggers.sqlite doit afficher un trigger, une acceptation et un event_id consommé.

6. Refuser un replay explicite​

Le runner produit ses propres event_id. Pour tester un replay de manière contrôlée, envoyez deux fois le même événement explicite avec un état dédié à ce test. On utilise un fichier séparé pour ne pas réutiliser le quota déjà consommé par le runner.

Premier passage :

Terminal
touba run morning-review.air.json \
--manifest touba.manifest.json \
--trigger-event-json '{"trigger_ref":"trigger:examples.trigger_morning_review/MorningReview","event_id":"evt-demo-replay","source_kind":"schedule"}' \
--state replay.triggers.sqlite \
--output trace

Deuxième passage avec le même event_id :

Terminal
if touba run morning-review.air.json \
--manifest touba.manifest.json \
--trigger-event-json '{"trigger_ref":"trigger:examples.trigger_morning_review/MorningReview","event_id":"evt-demo-replay","source_kind":"schedule"}' \
--state replay.triggers.sqlite \
--output json > replay-result.json; then
exit 1
else
test "$?" -eq 1
fi
node --input-type=module -e 'import assert from "node:assert/strict"; import {readFileSync} from "node:fs"; const r=JSON.parse(readFileSync("replay-result.json","utf8")); assert.equal(r.reason,"TriggerReplayRejected"); assert.ok(!r.trace.events.some(e=>e.kind==="trigger_execution_started")); console.log("TRIGGER_REPLAY_REFUSED_OK");'

Résultat attendu :

Erreur
trigger error [TriggerReplayRejected]

La stratégie n’est pas relancée. La trace contient trigger_event_refused avec la raison event_replay.

7. Tester les checks sans exécuter​

Le dry-run vérifie le trigger, le manifest et les limites sans lancer la stratégie.

Terminal
touba run morning-review.air.json \
--manifest touba.manifest.json \
--trigger-event-json '{"trigger_ref":"trigger:examples.trigger_morning_review/MorningReview","event_id":"evt-demo-001","source_kind":"schedule"}' \
--trigger-dry-run \
--output trace

Vous devez obtenir un rapport de checks acceptés, pas une trace d’exécution. Aucun message show n’est affiché, car la stratégie n’est pas exécutée en dry-run.

8. Provoquer un refus volontaire​

Créez un manifest désactivé :

touba.manifest.disabled.json
{
"manifest_version": "touba-manifest-v1",
"triggers": {
"trigger:examples.trigger_morning_review/MorningReview": {
"enabled": false,
"source": {
"kind": "schedule"
},
"limits": {
"max_runs_per_day": 1,
"timeout_ms": 30000
}
}
}
}

Puis lancez :

Terminal
if touba trigger run morning-review.air.json \
--manifest touba.manifest.disabled.json \
--trigger trigger:examples.trigger_morning_review/MorningReview \
--max-runs 1 \
--state touba.triggers.sqlite \
--output json > disabled-result.json; then
exit 1
else
test "$?" -eq 1
fi
node --input-type=module -e 'import assert from "node:assert/strict"; import {readFileSync} from "node:fs"; const r=JSON.parse(readFileSync("disabled-result.json","utf8")); assert.equal(r.reason,"TriggerDisabled"); assert.deepEqual(r.messages,[]); console.log("DISABLED_TRIGGER_REFUSED_OK");'

Résultat attendu :

Erreur
trigger error [TriggerDisabled]

Le runtime refuse avant d’entrer dans RunMorningReview. Aucun message show n’est produit.

9. Ce que vous avez réellement testé​

Ce tutoriel teste une première autonomie réactive :

  • le programme Touba déclare le déclenchement ;
  • l’environnement autorise explicitement ce déclenchement ;
  • le runner foreground attend un intervalle réel ;
  • l’état durable de trigger refuse un replay explicite ;
  • le runtime applique les checks avant l’exécution ;
  • la trace documente l’acceptation ou le refus.

Suite​

Pour les triggers request -> strategy avec service webhook HTTP, queue persistante, état durable, signature HMAC et dead-letter, voir Triggers gouvernés.

Ce scénario établit le modèle schedule -> strategy : déclenchement déclaré, état durable, refus de replay et trace exploitable.

Pour plusieurs runs planifiés, --output json retourne un tableau avec le statut et la raison de chaque run. La trace agrégée possède son identité ; origin_run_id et origin_event_id conservent la provenance des événements enfants. trigger_runner_run_started et trigger_runner_run_completed délimitent chaque enfant. Le runner s’arrête à la première pause, interruption, annulation ou erreur ; il ne poursuit pas silencieusement et n’annonce pas un succès global.