Process automation
Process automation: hoe één hernoemde variabele 412 DM's verstuurde
Een junior engineer bij een Gents recruitmentbureau hernoemde één variabele in een Make.com-scenario. Negen dagen later hadden 412 LinkedIn-kandidaten de verkeerde vacature gehad. Dit is precies wat misging.

Het eerste bericht kwam van een klant. Dinsdagochtend, 09:14, een Slack-ping naar de oprichter van een recruitmentbureau van 19 mensen in Gent, wiens sourcing-automation veertien maanden onaangeroerd had gedraaid: "Waarom kregen drie van mijn engineers van jullie een DM over een Java-rol? We hebben jullie ingehuurd voor de Go-positie."
Binnen een uur zeiden twee andere klanten iets soortgelijks. Tegen de lunch had het bureau gereconstrueerd wat er de afgelopen negen dagen was gebeurd. Hun Make.com-scenario, dat kandidaten uit LinkedIn Sales Navigator haalde en de eerste DM verstuurde, had stilletjes 412 mensen een DM gestuurd met de titel van de verkeerde vacature. Elk bericht was netjes, on-brand en persoonlijk. Alleen de baan klopte niet.
Deze post is de post-mortem. We hebben de naam van het bureau en een paar kentekencijfers aangepast. Alles wat ertoe doet aan de fout is echt.
Het scenario dat het team dacht te hebben
Het oorspronkelijke Make.com-scenario was zo simpel als een sourcing-pipeline maar kan zijn. Een trigger ging af zodra een recruiter een kandidaat in een Notion-lijst zette met het label "ready-to-contact". Een lookup-module haalde de bijbehorende vacature uit een tweede Notion-tabel. Een "Set variable"-stap zette de vacaturetitel klaar voor later in de run. Een LinkedIn-module stuurde vervolgens de DM, met een persoonlijke openingszin vóór de titel.
Dit scenario draaide veertien maanden onaangeroerd. Het sourcing-volume piekte op drukke weken rond 60 kandidaten per dag. Het team vertrouwde het zoals je een waterkoker vertrouwt: je controleert niet of hij gekookt heeft.
De hernoeming
Twee weken vóór het incident was een junior automation-engineer aan het opruimen. Het scenario had een zusje gekregen: een tweede variant voor één klant die een andere openingszin wilde. Beide varianten gebruikten een variabele genaamd vacancyTitle. De junior, die het verschil terecht in één oogopslag duidelijk wilde maken, hernoemde de variabele in de tweede variant naar vacancyTitle_clientX.
Dat deel was prima. Tijdens het opruimen hernoemde hij ook de live Set Variable-stap in het oorspronkelijke scenario van vacancyTitle naar vacancyTitle_main, want dat vond hij netter. Hij dacht dat hij elke plek waar de variabele werd gelezen had bijgewerkt. Eén plek had hij gemist. Het bericht-template van de LinkedIn-module, zes modules later, verwees nog steeds naar {{vacancyTitle}}.
Nu komen we bij de spook-stap. Maanden eerder had iemand bovenin het scenario een Set Variable-stap toegevoegd als debug-fallback, waarin vacancyTitle hard was gecodeerd op "Senior Java Developer", zodat het team de rendering van berichten kon testen zonder echte record. Die stap was nooit verwijderd.
Vóór de hernoeming overschreef de live writer verderop in het scenario de debug-waarde bij elke run, dus het spook was onschadelijk. Na de hernoeming was het spook het enige dat nog naar vacancyTitle schreef. Het LinkedIn-template las het vrolijk uit. Elke kandidaat, ongeacht rol, ongeacht klant, ongeacht welk scenario de DM verstuurde, kreeg "Senior Java Developer".
Waarom niemand het negen dagen zag
Drie dingen verborgen de fout.
Ten eerste rapporteerde het scenario groen. De run history van Make toont per run een execution-status, en elke run voltooide zonder error. De LinkedIn-DM-module gaf een succesvolle response terug. De kandidaat ontving het bericht. De operations-teller tikte door. Vanuit het dashboard werkte de automation precies zoals altijd.
Ten tweede liep de antwoord-loop niet via hetzelfde scenario. Reacties kwamen binnen in de LinkedIn-inbox, waar een ander teamlid ze triageerde. Toen een paar kandidaten antwoordden met "volgens mij is dit de verkeerde rol?", werden die berichten als losse mismatches behandeld en werden de kandidaten netjes doorverwezen. Niemand legde dwars door de dagen heen het verband.
Ten derde, en dit is het stuk dat een kleine bug in een bug van negen dagen veranderde: het zoeken in de Make run history is beperkt tot één scenario per keer. Je kunt niet door al je scenario's en mappen heen greppen op de string "Senior Java Developer" en vragen welke runs die string ooit in hun output hadden. Wie ooit vijf minuten in de Make help-docs heeft gezeten, weet dat run history één execution per keer is, één scenario, één scherm. Voor een audit-vraag als "welke van onze scenario's heeft ooit string X naar LinkedIn gestuurd" open je elk scenario en doorzoek je elke run apart.
Geen van deze drie failure modes is uniek voor Make. Dezelfde combinatie zien we op elk low-code platform dat we hebben geaudit: stille default-behavior bij ontbrekende of stale waarden, zoeken per resource in plaats van cross-corpus, en een scheiding tussen het systeem dat verstuurt en het systeem dat antwoorden ontvangt. Elk van die drie is op zichzelf redelijk. Samen vormen ze een muur waarachter stille fouten lang kunnen leven.
Blast radius
Toen we op dag tien bij de oprichter aanschoven, was de blast radius helder. 412 kandidaten hadden de verkeerde vacaturetitel in hun eerste DM gehad. 37 hadden geantwoord: meestal verward, een handvol geïrriteerd. Twee vroegen expliciet om uit elk toekomstig contact verwijderd te worden. Eén had de DM gescreenshot en op LinkedIn gezet met als bijschrift "dit is waarom ik recruiters niet vertrouw". De post stond tegen lunchtijd op een paar duizend reacties en de meeste comments waren mensen die hun eigen versie van hetzelfde verhaal deelden.
De opruiming
De eerste reflex van het bureau was om alle 412 mensen excuses aan te bieden. Dat was juist, en ze deden het binnen 48 uur, met een korte persoonlijke noot van de oprichter per kandidaat. De tweede reflex was lastiger. Ze wilden weten welke kandidaat eigenlijk welke titel had moeten ontvangen, zodat de follow-up de specifieke baan kon benoemen, niet alleen "de verkeerde".
Hier deed het ontbreken van cross-scenario-zoeken in Make pijn. Om per kandidaat het audit-spoor te reconstrueren, hebben we via de Make API elke run-bundle uit het getroffen venster van negen dagen opgehaald, de input-bundles geparseerd en de mapping tussen kandidaat-ID en bedoelde-versus-verstuurde vacature opnieuw opgebouwd. Globaal:
# Pull execution bundles for one scenario across a date window.
# There is no cross-scenario query; you do this per scenario.
import os, time, requests
TOKEN = os.environ["MAKE_API_TOKEN"]
ZONE = "eu2.make.com" # use your own Make zone
def list_runs(scenario_id, start_iso, end_iso, page_size=100):
url = f"https://{ZONE}/api/v2/scenarios/{scenario_id}/executions"
offset = 0
while True:
params = {"from": start_iso, "to": end_iso,
"pg[limit]": page_size, "pg[offset]": offset}
r = requests.get(url, params=params,
headers={"Authorization": f"Token {TOKEN}"}).json()
items = r.get("executions", [])
if not items:
return
for ex in items:
yield ex
offset += page_size
time.sleep(0.3) # be kind to the API
def fetch_bundle(scenario_id, execution_id):
url = (f"https://{ZONE}/api/v2/scenarios/"
f"{scenario_id}/executions/{execution_id}")
r = requests.get(url, headers={"Authorization": f"Token {TOKEN}"})
r.raise_for_status()
return r.json()
Uit de bundles hebben we gejoind op de output van de LinkedIn-module, de gerenderde berichttekst uitgelezen en gezocht naar de letterlijke string "Senior Java Developer" op plekken waar die niet matchte met de echte vacature-ID van de kandidaat. Die join leverde de 412 op.
De fix
De patch zelf duurde twaalf minuten. We verwijderden de wees-debug Set Variable bovenin, herstelden één canonieke naam en voegden een guard-stap toe die een expliciete error gaf als de opgehaalde vacaturetitel ontbrak, leeg was, of niet matchte met een vacature-ID in het record van de kandidaat. Die laatste check had er vanaf dag één moeten staan. Als de berichttekst naar een vacature verwijst, moet het scenario weigeren te versturen zodra die vacature niet te bevestigen is.
Het structurele werk was zwaarder.
Naming-hygiëne
Het variabelensysteem van Make is in de verkeerde richting vergevingsgezind. Het waarschuwt je niet voor een wees-variabele, een stale write of een naam-botsing in dezelfde map. We hebben een conventie ingevoerd: elke variabele die in een klantgericht bericht wordt gebruikt, volgt het patroon scenarioName_purpose, heeft precies één writer, heeft elke reader gedocumenteerd in de scenario-notities en wordt opnieuw bekeken bij elke wijziging van het scenario. Saaie regels betalen zich uit zodra iemand nieuw aansluit, en het meest op de dag dat de bouwer in een vliegtuig zit.
Eén bron van waarheid voor de berichttekst
Het oorspronkelijke scenario bouwde de DM-tekst op uit een template in de UI van de LinkedIn-module. Een tekstwijziging betekende Make openen. We hebben de berichttekst verplaatst naar een rij in dezelfde Notion-tabel waarin de vacature stond. Het scenario leest nu direct {{vacancy.message_body}}. Berichttekst en vacaturetitel delen dezelfde rij, dus ze kunnen niet uit elkaar lopen.
Een canary buiten het platform
Wat de bug uiteindelijk opving was een betalende klant. Dat wilden we niet als detectiemechanisme houden. We voegden een klein canary-scenario toe: elke 30 minuten duwt het een nep-kandidaat door de sourcing-pipeline, waarbij de DM-stap is vervangen door een webhook naar een server van ons. Die server vergelijkt de gerenderde berichttekst met de verwachte output voor die vacature. Is de diff niet leeg, dan piept hij.
Dit is een bekend patroon voor iedereen die ooit een productie-service heeft gedraaid. Voor de meeste kleine teams is Make.com of n8n of Zapier hun productie-service. Het verdient dezelfde observability.
Als je no-code platform niet door mappen en scenario's heen kan greppen op een string die naar een klant is gestuurd, heb je geen audit trail. Je hebt een verhaal dat je team zichzelf vertelt.
Het bredere patroon
De week dat we deze draft schreven, stonden er op de voorpagina van Hacker News meerdere varianten van hetzelfde gesprek: een AI-agent die over een Fedora-installatie en een paar andere systemen heen had geschreven, een discussie over guardrails op commerciële agent-platforms, en de opkomst van Burr van DAGWorks als framework voor agents waar je doorheen kunt tracen. De vorm van al die threads is dezelfde als die het recruitmentbureau op dag tien had. Op het moment dat automation echt werk doet op echte mensen, is "de run kwam groen terug" niet genoeg.
Het argument dat de agent-tracing-community blijft maken is het juiste: elke externe actie die je automation onderneemt moet achteraf reconstrueerbaar zijn, idealiter uit één query. Een no-code scenario dat 60 DM's per dag verstuurt is structureel een agent. Het krijgt input, neemt beslissingen, heeft effect in de echte wereld. Als je niet in één query kunt vragen "wat heeft het gedaan en waarom?", vlieg je blind.
Wat je minimaal nodig hebt: een audit trail die je over runs en scenario's heen kunt queryen, een canary die los staat van de eigen health check van het platform, en een weigerregel bij versturen die luider is dan het groene vinkje. Geen van die drie is spannend om te bouwen. Alle drie hadden negen dagen tot één dag teruggebracht.
De audit van vijf minuten
Als je een Make.com-, n8n- of Zapier-opstelling hebt die berichten naar mensen stuurt, dan kun je vandaag deze audit doen. Kies drie scenario's. Schrijf voor elk de naam op van elke variabele die in een klantgericht bericht wordt gebruikt. Open het scenario, zoek op die naam en tel de writes en de reads. Heeft een naam meer dan één writer, of verwijst een reader naar een naam waar niets meer naar schrijft, dan heb je dezelfde opstelling als in Gent.
Toen wij de process automation voor het bureau opnieuw bouwden, liepen we ertegenaan dat het Make-scenario vier jaar aan kleine edits had opgebouwd zonder dat iemand de variable-graph beheerde. We hebben dat opgelost door message-templates naar Notion te halen en een canary toe te voegen die piept op diff, zodat de volgende vergeten debug-stap binnen 30 minuten wordt gepakt in plaats van negen dagen.
Vijf minuten zijn genoeg om uit te vinden of je eigen opstelling één hernoeming verwijderd is van dezelfde dinsdagochtend.
Kern
Als je automation niet over runs heen kan greppen op een string die naar een klant is verstuurd, is je audit trail een verhaal dat je team zichzelf vertelt.
FAQ
Wat veroorzaakte de foute-DM-bug precies?
Een junior hernoemde de live Set Variable-stap. Een oude debug-Set Variable bovenin het scenario, maanden eerder vergeten, bleef een stale titel doorgeven. Het LinkedIn-template gebruikte die stale waarde stilletjes.
Waarom duurde de bug negen dagen?
Elke run rapporteerde groen, antwoorden kwamen binnen in een aparte inbox die door iemand anders werd getriageerd, en Make.com heeft geen cross-scenario-zoekfunctie in run history om op de verkeerde string te greppen.
Hoe voorkom je dit op Make.com?
Verplaats templates naar één bron van waarheid, voer een conventie in met één writer per variabele, voeg een expliciete weiger-te-versturen-guard toe en draai een canary buiten het platform die de gerenderde output diffr tegen verwacht.
Is dit specifiek voor Make.com?
Nee. Elk low-code platform zonder cross-run-zoeken, expliciete errors bij ongezette variabelen en één samenhangende reply-loop is kwetsbaar voor hetzelfde stille-fout-patroon. Make is alleen waar dit verhaal zich afspeelde.