Concept

Runtime et Inbound

nekostronaut.com est un runtime orienté événements. Le point structurant dans le code actuel est que tout n’est pas un agent: le Supervisor route certains événements vers un agent d’exécution, tandis que la persistance des séquences, le scheduling et plusieurs transitions d’état vivent dans des workers dédiés.

Topologie du runtime

Supervisor

Routeur statique qui mappe un événement supporté vers un seul agent d’exécution, puis applique la politique et attache les insights pré-calculés.

Agents d’exécution

Six agents sont instanciés dans le runtime: `lead_finder`, `personalization`, `sequence`, `reply`, `demo` et `closer`.

Workers hors agents

Le séquencement, la traversée des steps, la gestion de l’engagement, le no-show et le calcul d’insights sont portés par des workers dédiés hors Supervisor.

Événements effectivement routés

ÉvénementPropriétaireComportement actuel
lead.createdlead_finderQualifie et enrichit le lead, puis peut émettre `lead.scored`.
lead.scoredpersonalizationEnvoie directement le premier message outbound, puis émet `sequence.started`.
sequence.startedSequenceStarterCrée les lignes de séquence et l’état initial des steps. Cet événement n’est pas routé par le Supervisor.
sequence.step_duesequenceExécute les relances ou autres actions quand le scheduler déclare un step à échéance.
nurture.triggeredsequencePasse par le même SequenceAgent pour le nurturing post-démo ou post-engagement.
inbound.receivedreplyClasse le message inbound, répond quand c’est sûr, ou escalade.
demo.sentdemoEnvoie l’email compagnon de démo et enregistre l’état de la démo.
demo.viewed / meeting.booked / meeting.cancelledcloserFait avancer le lead vers le closing, la reproposition de rendez-vous ou le handoff humain.

Cas limites à connaître

`lead.enriched` est encore souscrit

Le worker s’abonne toujours à `lead.enriched`, mais le Supervisor ne route pas cet événement vers un agent. En pratique, il n’alimente donc pas la chaîne d’exécution standard.

Le routage inbound échoue proprement

Si aucun workspace unique n’est résolu, ou si aucun lead ne matche l’expéditeur après résolution du workspace, le webhook est acquitté sans créer de conversation fantôme.

Ordre de routage inbound

Le webhook inbound email privilégie volontairement la conversation. L’app fait d’abord confiance au thread avant de faire confiance à l’adresse expéditeur, et elle échoue proprement si le routage reste ambigu.

1. Le thread d’abord

Si Postmark fournit un `In-Reply-To` ou `References` pointant vers un message outbound connu, l’email inbound est rattaché à cette conversation avant tout contrôle sur l’adresse expéditeur.

2. Résolution du workspace ensuite

S’il n’y a pas de thread, l’app résout d’abord le workspace via l’adresse destinataire exacte, puis via le domaine inbound configuré.

3. Matching expéditeur exact en dernier

Dans le workspace résolu, l’app cherche ensuite un lead par égalité exacte sur l’email expéditeur. Sans match, le webhook est acquitté mais aucune conversation ni exécution agent n’est créée.

Qui pilote les séquences

Le séquencement outbound est réparti entre agents et workers. Le premier message est porté par un agent, mais le scheduling durable et la progression sont gérés par des workers.

1

Premier contact

`Personalization` envoie le premier message outbound sur `lead.scored`.

2

Création durable de la séquence

`SequenceStarter` crée `sequences` et `sequence_steps` après ce premier contact.

3

Polling des steps

`SequenceScheduler` sonde les lignes en attente et émet `sequence.step_due` lorsqu’un step atteint `scheduled_at`.

4

Progression et traversée

En mode flow, `MessageSentHandler` marque le step complété et `StepCompletionHandler` traverse le graphe. La couverture du mode historique est plus limitée.

5

Interruption par l’inbound

Une réponse inbound normale annule les séquences actives; un out-of-office les met en pause.

Garde-fous

Le Supervisor est déterministe et auditable, mais ce n’est pas un planner.

Le routage inbound est à échec fermé: un destinataire ambigu ou un expéditeur non reconnu ne crée pas de conversation fantôme.

La chaîne outbound effective est `lead.created -> lead_finder -> lead.scored -> personalization`.

Les playbooks en mode flow sont la forme runtime la plus solide; les steps historiques ordonnés s’exécutent encore.