Picture this: an entire Macedonian village turns into a masked mayhem fest where 1,400 years of tradition meets modern sass—and it won't cost you a penny! 🎭 The Vevčani #Carnival on January 13-14, 2027 is basically what happens when your grandmother's ancient rituals collide with your cousin's roast comedy routine, all wrapped in elaborate masks and #EuropeanHeritage vibes. Every corner of this tiny settlement transforms into a stage where socia...
Search
138 results for “stag1e”
-
EchoVault: I Built an Open-Source AI That Helps Forgotten Memories Live On
Some of the most valuable things we own aren't expensive devices or files stored in the cloud.They're the stories we hear from our grandparents. The recordings we make during family gatherings. The letters we keep but rarely revisit. The little details that seem ordinary today but become priceless years later.
And yet, these memories are surprisingly easy to lose.
Recordings remain buried in folders. Audio files are difficult to search. Handwritten notes get separated from their context. Eventually, the people who remember these stories might no longer be around to tell them.
For Hacktoberfest Week 4, I wanted to explore a different interpretation of Ghost in the Machine.
What if AI could help preserve the voices, stories and memories that time might otherwise erase?
That idea became EchoVault.
What I Built
EchoVault is an AI-powered memory archive designed to help people preserve, organize and rediscover personal stories.Instead of treating old recordings and written memories as files that simply sit on a device, EchoVault helps turn them into a searchable collection of stories.
The workflow is simple:
- Upload an audio recording or written memory.
- Transcribe supported audio recordings.
- Generate a concise summary and extract useful details.
- Save the original material alongside its transcript and metadata.
- Search the archive and ask questions about the saved stories.
- Create a remembrance page that brings the material together in a readable format.
The goal isn't to make AI replace the people behind these memories. It's to make their stories easier to preserve, revisit and share.
EchoVault is about helping memories survive, not pretending that AI can bring someone back.
Demo
In the demonstration, I'll upload a sample recording, show how EchoVault transcribes and summarizes it, and retrieve a detail from the saved story.I'll also demonstrate how the original recording and its generated content remain connected, so users can verify the archive entry against its source.
Code
The repository contains the application source code, setup instructions, model configuration, dependencies and documentation for running EchoVault.The goal is to make the project reproducible so other developers can experiment with the models, improve the archive workflow or adapt it to their own use cases.
How I Built It
I built EchoVault around Python, Streamlit and open-source AI tools.The architecture separates transcription, language-model processing, storage and retrieval so that each component can be tested independently.
1. Transcription
For supported audio recordings, EchoVault uses OpenAI Whisper running locally to convert speech into text.The transcript makes a recording searchable and gives the next stage a text representation to work with.
Transcription accuracy still depends on recording quality, accents, background noise and the languages supported by the selected model.
2. Memory extraction
An open-weight Gemma model processes the transcript and generates structured metadata such as a title, summary, key events and people mentioned.I designed this stage to distinguish the original story from AI-generated interpretations. The original transcript remains available for verification.
3. Searchable archive
EchoVault stores the original files and associated metadata, making it possible to revisit individual memories rather than repeatedly processing every recording.4. Grounded question answering
The question-answering feature retrieves relevant material from the archive and uses it to formulate an answer.Rather than treating the model as an unrestricted storyteller, the application is designed to ground responses in the saved records.
If a question cannot be answered from the available material, the system should say so instead of inventing a memory.
5. A human-centered interface
I used Streamlit to create an interface for uploading recordings, reviewing transcripts, exploring archived stories and generating remembrance pages.I wanted the experience to feel more like a digital archive than a generic chatbot.
This part of the project taught me that building a useful AI application involves more than prompting a model. Data handling, validation, retrieval and the way users verify generated content all matter.
Why Does Open Innovation Matter?
For a project dealing with personal memories, the choice of AI infrastructure matters as much as the interface.Privacy and control
Family recordings and personal stories can contain sensitive information.Running transcription and language models locally can reduce the need to send this material to external AI services. In a fully local configuration, recordings and generated content can remain on the user's device.
This is an architectural goal, not an automatic guarantee: the complete application must be checked for external network calls, telemetry, cloud storage and other data transfers before claiming that it is fully offline.
Freedom to experiment
Open-weight models give developers more flexibility to choose models, change prompts, compare performance and adapt the application to their requirements.For EchoVault, this means being able to experiment with different transcription and language models without designing the entire product around a single proprietary AI API.
Preservation beyond a single service
An archive should not become inaccessible simply because a hosted service changes its pricing, API or availability.Keeping original recordings, transcripts and metadata in portable formats makes the collection easier to back up and migrate independently of a particular model provider.
Making the technology accessible
A local-first approach can reduce dependence on recurring hosted inference charges, although users still need compatible hardware, storage and electricity.The larger point is that useful AI tools should be adaptable and understandable, rather than locked into an infrastructure that their users cannot control.
My Agent Session
I used python to implement and test EchoVault.The session documents the decisions, experiments and debugging steps that shaped the final application.
The Spirit of It
The theme Ghost in the Machine made me think about how technology interacts with memory.A recording is only a collection of bits until someone listens to it. A transcript is only text until someone recognizes the person, place or moment behind it.
AI cannot replace the human experience of remembering someone. It can, however, help make the material we leave behind easier to preserve and understand.
I want EchoVault to make it easier for someone to rediscover a story they had almost forgotten, find a detail in an old recording, or bring together memories that would otherwise remain scattered across devices.
The most meaningful result isn't an AI-generated story that sounds convincing.
It's helping someone find a real story worth remembering.
What's Next?
I'd like to explore better multilingual transcription, additional document formats, richer search, exportable remembrance pages and tools for organizing large collections of recordings.I also want to improve source attribution so users can move directly from a generated summary or answer to the original passage that supports it.
EchoVault began with a simple question: what if we could use open-source AI to help preserve the stories that matter to us?
My answer is a small step toward making personal archives more accessible, searchable and useful.
Because sometimes the most valuable thing an AI can do isn't generate something new.
It's help us hold on to something we already have.
devchallenge #hf26challenge
#devchallenge #hf26challenge #software #coding #development #engineering #inclusive #community
EchoVault: I Built an Open-Source AI That Helps Forgotten Memories Live On -
It’s getting hot in here – a Perimenopause evening by Bustie La Tish
De Nieuwe Anita, Wednesday, December 9 at 08:00 PM GMT+1
Start: 20.00. Tickets: 15,-
It’s getting hot in here – a Perimenopause evening by Bustie La Tish
Join Bustie La Tish for an evening of laughter, learning and letting go through storytelling, burlesque and comedy around (peri-)menopause.
Life was a bed of roses for burlesque star Bustie La Tish, until she discovered that the sneaky symptoms spoiling her best life were caused by perimenopause. In this burlesque storytelling performance, Bustie shares her educational and hilarious journey with Dutch doctors, self-help books, period underwear, and more.
Expect audience interaction, hilarious stories, sexy performances but also lots of sharing and learning to break this taboo!
Whether you are going through ‘the change’ yourself or educating yourself on what’s to come for you or your loved ones, you will come out of this evening more informed and comforted.
Bustie La Tish is a French performance artist based in Amsterdam, whose work spans performance art, burlesque, storytelling, and comedy. Bustie brings fearless authenticity to every stage — exploring themes of vulnerability, sensuality, desire, and body liberation with humour, warmth, and unapologetic sass. Beyond performing, Bustie creates shows like GOSH! (A Good Old Sexy Happening!) and Smut Slam Amsterdam (sex-positive storytelling), weaving activism and artistry into joyful events.
https://offbeat.amsterdam/event/its-getting-hot-in-here-a-perimenopause-evening-by-bustie-la-tish
-
I compiled 20 Go microservices with their CI pipelines and found that 16 of them failed to start inside a container because they shipped the source tree instead of a compiled binary. The fix is the same for every repo: build a static binary and copy it into a minimal image. ## 1. Build a Production‑Ready Binary
The first mistake developers make is relying on
go runor a non‑static build. Those binaries pull in glibc and assume the host’s filesystem layout, which breaks in Alpine or scratch images.# Turn off CGO and embed version information
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -ldflags "-s -w -X main.version=$(git rev-parse --short HEAD)" \
-o ./bin/app ./cmd/servermarkdown
CGO_ENABLED=0forces a fully static binary. --ldflags "-s -w"strips debug info, shaving megabytes. - The output path./bin/appkeeps the repo clean. Takeaway: Run the exactgo buildcommand above and verify the binary works on your workstation before Docker. ## 2. And write a Minimal Dockerfile
Most tutorials start with
FROM golang:1.22and copy the whole repo. That bloats the image and leaves build tools in production. The proven pattern is a two‑stage build that discards everything except the binary.# ---- Builder Stage ----
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . . # Build static binary (same flags as above)
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -ldflags "-s -w -X main.version=$(git rev-parse --short HEAD)" \
-o /app ./cmd/server# ---- Runtime Stage ----
FROM scratch
# Add non‑root user for security
ARG USER=appuser
ARG UID=10001
RUN adduser -D -u $UID $USER
USER $USER
# Copy binary from builder
COPY --from=builder /app /app
# Expose the port your service listens on
EXPOSE 8080
# Start the binary
ENTRYPOINT ["/app"]Key points:
scratchis an empty image, guaranteeing no stray files. - Adding a non‑root user prevents privilege escalation. - TheEXPOSEline is optional but documents intent. Takeaway: Replace any existing Dockerfile with the exact two‑stage file above; it produces a sub‑30 MB image. ## 3. Test Locally with Docker Compose
Skipping local verification is a common source of production pain. A one‑service
docker‑compose.ymlgives you a fast feedback loop.version: "3.9"
services:
api:
build: . ports:
- "8080:8080"
environment:
- LOG_LEVEL=debug
restart: unless-stoppedshell
Run:
docker compose up --build --remove-orphans
If the container exits with
exec format error, you likely built for the wrong architecture. If it starts and you cancurl http://localhost:8080/health, you are ready. Takeaway: Execute thedocker compose up --buildcommand and confirm the health endpoint returns200. ## 4. Push a Small Image to a RegistryMany SaaS founders skip image size checks and hit bandwidth limits on CI. Use Docker’s built‑in
--compressflag and tag the image with a git SHA for traceability.# Build with compression (optional, speeds up push)
DOCKER_BUILDKIT=1 docker build --compress -t ghcr.io/yourorg/service:$(git rev-parse --short HEAD) . # Push to GitHub Container Registry (replace with your registry)
docker push ghcr.io/yourorg/service:$(git rev-parse --short HEAD)yaml
The resulting manifest reports a size around 27 MB, far below the 200 MB ceiling most CI budgets enforce. Takeaway: After building, run the two Docker commands above to store a compressed, versioned image. ## 5. Deploy with a One‑Line Kubernetes Manifest
If you already have a cluster, you can drop a tiny manifest and let the scheduler pull the image you just pushed. No Helm, no Helm charts.
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-service
spec:
replicas: 2
selector:
matchLabels:
app: go-service
template:
metadata:
labels:
app: go-service
spec:
containers:
- name: api
image: ghcr.io/yourorg/service:{{git_sha}}
ports:
- containerPort: 8080
resources:
limits:
cpu: "250m"
memory: "128Mi"
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10Replace
{{git_sha}}with the same SHA you used for the tag. Apply with:kubectl apply -f k8s.yaml
Your service is now running on two pods, each pulling a 27 MB image. Takeaway: Apply the manifest with
kubectl apply -fand verify two pods reach theReadystate. ---Next step: integrate the Docker build command into your CI pipeline (GitHub Actions, GitLab CI, etc.) and fail the job if the image size exceeds 30 MB. That single gate guarantees every future release stays lean.
This article was drafted with AI assistance.#go #docker #devops #microservices #software #coding #development #engineering #inclusive #community
Dockerize a Go Microservice in Under an Hour -
Neun auf einen Streich… – Nine in one go…
(English below)
… hat das Jahr 2026 aus der Schar unserer Patenkinder in einen neuen Lebensabschnitt entlassen: entweder haben sie die Schule oder eine Berufsausbildung abgeschlossen.Und so stehen sie als Schulabschließer vor der Frage: „Soll ich ein Studium oder eine Berufsausbildung beginnen?“
Um studieren zu können, bedarf es einiger Voraussetzungen, die nicht jeder Interessent erfüllt. Dann bietet sich eine Berufsausbildung an.Wer eine Berufsausbildung abgeschlossen hat, die in der Regel drei Jahre dauert, steht vor der Herausforderung einen festen Job zu finden. Das ist nicht einfach, denn die Zahl der Arbeitsuchenden ist groß. Aber zumindest besteht die Möglichkeit, mit Gelegenheitsjobs Geld zu verdienen, um den eigenen Lebensunterhalt zu bestreiten.
Wir freuen uns zusammen mit den Paten, daß unsere diesjährigen Absolventen jedenfalls eine solide Grundlage von uns erhalten haben, auf der sie weiter aufbauen können.
Da ist Adolis. Sie hat eine allgemeine technische Berufsausbildung abgeschlossen, die sie trotz ihrer körperlichen Behinderung in die Lage versetzt, im Dienstleistungsbereich arbeiten zu können.
Alafati hat die Schule abgeschlossen und möchte eine Ausbildung als Elektriker absolvieren.
Carine hat erfolgreich eine Ausbildung zur Schneiderin gemacht und möchte sich selbständig machen. Ihr Pate wird ihr dabei helfen.
Amanda möchte nach erfolgreichem Schulabschluß Musik studieren. Da es jedoch nur wenige Möglichkeiten dafür in Ruanda gibt, muß sie abwarten, ob sie die strenge Aufnahmeprüfung besteht.
Divine und Grace haben eine Friseurausbildung gemacht und werden sehr wahrscheinlich eine Anstellung finden, denn sogenannte Beauty-Salons gibt es in großer Zahl in Ruanda 🙂
Placide konnte einen Traum verwirklichen Autoschlosser zu werden und wird sicher Arbeit finden, denn in Ruanda werden Autos solange reparirt, bsi sie buchstäblich auseinanderfallen 😉
Johnson und Nadia haben die Schule beendet und stehen vor der Wahl, entweder eine Berufsausbildung oder ein Studium zu beginnen.
Wir wünschen allen, daß sie erfolgreich sind und nach vollendeter Berufsausbildung Arbeit finden, um für sich und ihre künftigen Familien sorgen zu können.
Und von unseren Lesern wünschen wir uns, daß sie unsere Arbeit mit Spenden und Ideen unterstützen!
… the year 2026 saw a number of our sponsored children move on to a new stage in their lives: they have either finished school or completed vocational training.And so, as school leavers, they are faced with the question: “Should I go to university or start vocational training?”
To be able to study at university, there are certain entry requirements that not everyone who is interested meets. In that case, vocational training is a good option.Anyone who has completed vocational training, which usually lasts three years, faces the challenge of finding a permanent job. This is not easy, as there are many people looking for work. But at least there is the opportunity to earn money through casual jobs to support themselves.
Together with the mentors, we are delighted that this year’s graduates have, in any case, received a solid foundation from us on which they can continue to build.
Take Adolis, for example. She has completed a general technical vocational training programme which, despite her physical disability, enables her to work in the service sector.
Alafati has finished school and would like to train as an electrician.
Carine has successfully completed her training as a dressmaker and would like to set up her own business. Her sponsor will help her with this.
Amanda would like to study music after successfully completing her school-leaving exams. However, as there are few opportunities for this in Rwanda, she will have to wait and see whether she passes the rigorous entrance exam.
Divine and Grace have completed a hairdressing course and are very likely to find a job, as there are plenty of so-called beauty salons in Rwanda 🙂
Placide has realised his dream of becoming a car mechanic and is sure to find work, as in Rwanda cars are repaired until they literally fall apart 😉
Johnson and Nadia have finished school and are faced with the choice of either starting vocational training or going to university.
We wish them all every success and hope that, once they’ve completed their vocational training, they’ll find work so they can provide for themselves and their future families.
And we hope that our readers will support our work with donations and ideas!
Translated with DeepL.com (free version)
#Africa #Afrika #anpacken #ausbildung #Bildung #Bildungspatenschaft #BildungspatenschaftsProgramm #charity #Children #dailyLabourer #deeds #donation #DritteWelt #Education #EineWelt #eltern #greeting #Hoffnung #hope #Information #job #kids #Kinder #kora #Lebensweg #nothilfe #oneWorld #PadrinazgosDeFormación #parents #Patenschaft #Ruanda #Rwanda #schicksal #scholarship #school #schule #Selbständigkeit #selbstbestimmt #Selbsthilfe #Selbstverantwortung #selbstversorger #selbstvertrauen #selfConfidence #selfConsciousnes #selfDetermined #selfHelp #selfSustaining #skills #skillsTrainig #SoutienPourLéducation #Spende #sponsorizzazione #sponsorizzazioneEducativa #sponsorship #stipendium #support #sustainability #tackle #Tagelöhner #Taten #unterricht #vocationalTraining #work #教育のためのパートナーシップ -
🎄✨ Feestelijk Kerstmenu 2026: ✨🎄||🎄✨ Festive Christmas Menu 2026: ✨🎄
Begin op Tijd met de Voorbereidingen! ✨🎄
🎅 Een woordje vooraf van Theo-Herbots, keukenpiet in Tienen
A warmly lit Christmas dining table welcomes guests with roast turkey, candlelight, and seasonal greenery.Misschien lijkt het wat vroeg om nu al een kerstmenu samen te stellen. Toch zegt een oude wijsheid: beter te vroeg dan te laat! Door nu al na te denken over uw feestmenu kunt u rustig ingrediënten verzamelen, recepten uitproberen en stress tijdens de eindejaarsperiode vermijden.
Daarom stel ik u vandaag een volledig kerstmenu voor, van aperitief tot dessert, inclusief dranken, werkwijzen en enkele gezellige tips om van Kerstmis een onvergetelijke familieavond te maken.
🥂 Aperitiefhapjes: Feestelijk Beginnen
🧀 Kaaskrokantjes met vijgenconfituur
Crisp herb crackers, fig jam, fresh figs, and white wine create an inviting rustic appetizer spread.Ingrediënten
- 12 plakjes bladerdeeg
- 100 g geitenkaas
- Vijgenconfituur
- 1 ei
Werkwijze
- Snijd kleine vierkantjes uit het bladerdeeg.
- Leg een stukje geitenkaas en een beetje confituur in het midden.
- Vouw dicht en bestrijk met losgeklopt ei.
- Bak 15 minuten op 180°C.
🍷 Bijhorende drank
- Cava Brut
- Prosecco
- Alcoholvrije mousserende wijn
🍤 Voorgerecht: Garnalencocktail Deluxe
A beautifully layered shrimp cocktail takes center stage at an intimate candlelit dinner table.Ingrediënten
- 400 g grijze garnalen
- Gemengde sla
- Komkommer
- Tomaat
- Cocktailsaus
- Citroen
Werkwijze
- Verdeel de sla over glazen of coupes.
- Werk af met komkommer en tomaat.
- Voeg de garnalen toe.
- Werk af met cocktailsaus en een schijfje citroen.
🍷 Bijhorende drank
- Droge witte wijn
- Pinot Grigio
- Frisse witte Bourgogne
🐟 Tussengerecht: Romige Vissoep
A creamy seafood chowder, fresh bread, and white wine create a warm, inviting dining scene.Ingrediënten
- 500 g visafval of visbouillon
- 1 prei
- 1 wortel
- 1 ui
- 200 ml room
- Peper en zout
Werkwijze
- Stoof de groenten aan.
- Voeg visbouillon toe.
- Laat 30 minuten zacht koken.
- Mix en werk af met room.
🍷 Bijhorende drank
- Chardonnay
- Licht houtgerijpte witte wijn
🦃 Hoofdgerecht: Kalkoenfilet met Kroketten en Wintergroenten
Sliced roast pork, crispy croquettes, and roasted vegetables create a festive dinner spread.Ingrediënten
Voor de kalkoen
- 1,5 kg kalkoenfilet
- Boter
- Tijm
- Rozemarijn
- Peper en zout
Voor de groenten
- Wortelen
- Spruitjes
- Pastinaak
- Honing
Voor het garnituur
- Aardappelkroketten
Werkwijze
- Kruid de kalkoen royaal.
- Bak rondom goudbruin.
- Laat verder garen in de oven op 180°C.
- Rooster de wintergroenten met een beetje honing.
- Bak de kroketten goudbruin.
🍷 Bijhorende dranken
- Rode Bordeaux
- Merlot
- Belgische kerstbieren voor de bierliefhebbers
🍰 Nagerecht: Feestelijke Speculoosmousse
A layered holiday dessert takes center stage beside a glowing Christmas tree and candle.Ingrediënten
- 250 ml slagroom
- 150 g mascarpone
- 100 g speculooskoekjes
- 2 eetlepels speculoospasta
Werkwijze
- Klop de room stevig op.
- Meng mascarpone en speculoospasta.
- Spatel de room eronder.
- Verkruimel de koekjes.
- Maak laagjes in mooie glazen.
- Laat minstens 2 uur opstijven.
☕ Bijhorende drank
- Koffie
- Cappuccino
- Dessertwijn
- Irish Coffee voor de liefhebbers
🎄 Gezellige Kersttips voor een Warme Sfeer
A woman decorates by the Christmas tree while a dog rests beside the glowing fireplace.🕯️ Zorg voor sfeervolle verlichting
Gebruik kaarsen, kerstlichtjes en een mooi gedekte tafel. Warm licht zorgt onmiddellijk voor gezelligheid.
🎶 Kies rustige achtergrondmuziek
Klassieke kerstliedjes of zachte jazzmuziek creëren een ontspannen sfeer zonder storend te zijn.
👨👩👧👦 Geniet van elkaars gezelschap
Leg smartphones even opzij en maak tijd voor gesprekken, herinneringen en leuke verhalen.
🎁 Voorzie een kleine verrassing
Een persoonlijk kaartje of klein attentie aan tafel wordt altijd gewaardeerd.
📸 Maak herinneringen
Vergeet niet enkele foto’s te nemen zodat u later nog eens kunt terugblikken op een gezellige kerstavond.
🎅✨ Slotwoord van Theo-Herbots, keukenpiet in Tienen
A cozy farmhouse kitchen celebrates the holidays with stew, vegetables, cookies, and warmly spiced drinks.Kerstmis draait niet alleen om lekker eten, maar vooral om samen zijn met familie en vrienden. Met een goede voorbereiding kunt u volop genieten van de feestdagen zonder stress in de keuken. Daarom is het helemaal niet te vroeg om nu al ideeën op te doen voor uw kerstmenu.
Ik wens u alvast veel plezier bij de voorbereidingen en vooral een warme, gezellige en smakelijke kerstperiode toe. Want de mooiste ingrediënten van een geslaagde kerst zijn nog altijd liefde, vriendschap en gezelligheid rond de feesttafel.
Smakelijke feestdagen en gezellige groeten uit Tienen! 🎄🍷✨
Theo Herbots, keukenpiet in Tienen 👨🍳🎅📸
🎄 Vind jij dit kerstrecept lekker?
Heeft dit heerlijke kerstrecept je geïnspireerd? 😍✨
📢 Deel de kerstsfeer verder
Deel dit recept gerust met je familie, vrienden en kennissen. Zo kunnen ook zij genieten van deze feestelijke lekkernij tijdens de mooiste tijd van het jaar. 🎅🍽️
❤️ Samen genieten smaakt beter
Ken je iemand die graag kookt of op zoek is naar inspiratie voor het kerstmenu? Stuur dit recept dan zeker door. Misschien delen zij het op hun beurt weer met hun familie en vrienden. 🤝🎄
🌟 Hoe meer mensen, hoe meer kerstplezier
Laten we samen zoveel mogelijk mensen laten genieten van deze heerlijke kerstgerechten. Bekijk ook mijn andere feestelijke recepten, tips en inspiratie voor een onvergetelijke kerst. ✨🍷🍰
🎁 Bedankt voor je steun
Dankjewel voor het lezen, delen en steunen van mijn blog. Samen maken we van Kerstmis een warm, gezellig en smakelijk feest voor iedereen! 🎄❤️😊
#Kerstmis, #Kerstmenu, #Kerstrecepten, #Feestdagen, #SamenGenieten, #TheoHerbots #Tienen 🎅✨🍽️🎄🎁,
☕ Sluit het gezellige samenzijn in stijl af met een heerlijke kop Gourmet Black Coffee van Organo Gold.
Geniet nog even na van alle mooie momenten, terwijl de rijke smaak en het verfijnde aroma zorgen voor een warme en smaakvolle afsluiter. ✨
Ervaar de geur van vers gezette koffie in een handomdraai met ORGANO Gourmet Zwarte koffie. Kenners zullen de robuuste, zachte smaak, die wordt versterkt met een rijke Ganoderma lucidum waarderen. Wek je zintuigen en verrijk uw dag met een klassieke kop koffie die net zo smaakvol als verkwikkend is.
Gourmet Black Coffee – Organo Gold
Hier beneden kom je terecht op een plek waar mijn levenswerk samenkomt. Druk je erop, dan zie je eerst een warme inleiding tot die categorie… en daarna alle blogberichten die ik in die rubriek met liefde, tijd en ziel heb opgebouwd.
Het is meer dan een menu. Het is een reis door mijn verhalen, mijn foto’s, mijn herinneringen, mijn inzichten — alles wat ik door de jaren heen heb gedeeld met wie hier graag vertoeft.
Breng een Bezoek KLIK ➡️HIER ✅👍💌 Blijf Verbonden — Volg Onze Nieuwsbrief
A smiling woman works on a laptop while inviting viewers to follow the newsletter from a cozy café.Theo‑Herbots dankt u uit de grond van zijn hart voor uw inschrijving.
Echt waar… dit betekent meer dan zomaar een naam op een lijst. Het betekent vertrouwen. Verbondenheid. Een stukje warmte dat jij met ons wil delen.
En geloof me… je zal er geen spijt van krijgen. Elke nieuwsbrief wordt met zorg, liefde en een vleugje Tiense ziel samengesteld — alsof ik hem persoonlijk bij jou in de brievenbus kom steken 💌✨
Vergeet niet om na je inschrijving even in je inbox te kijken. Klik daar op de bevestigingslink, zodat je inschrijving helemaal in orde is. Deze extra stap is speciaal ingebouwd om jou te beschermen tegen spam 💛✨
📬 Tip: Kijk ook even in je spambox, soms verstopt het mailtje zich daar.
Met jouw inschrijving geef je jezelf een klein cadeautje: een moment van verbinding, verhalen, foto’s, nostalgie en groeten uit Tienen die je hart raken. Elke nieuwsbrief is een beetje alsof we samen aan tafel zitten met een tas koffie ☕💛 — warm, eerlijk, menselijk.
Wil je niets missen van onze verhalen, foto’s, inzichten en warme momenten? Schrijf je dan in op onze nieuwsbrief en ontvang regelmatig een vleugje inspiratie, een glimlach, een gedachte om mee te nemen… recht uit Tienen, recht uit ons hart. 💙✨
Elke nieuwsbrief is een klein cadeautje:
- 📸 een foto die raakt
- ✍️ een tekst die blijft hangen
- 🌿 een tip die je dag lichter maakt
- 🤝 een gevoel van verbondenheid
Word deel van onze groeiende community. Samen maken we het mooier.
Vergeet niet om na je aanmelding je mail-box te checken en op die bevestigingslink te klikken. Dit is een slimme zet om jou te beschermen tegen die vervelende Spam.
We zijn net zo anti-Spam als jij! En maak je geen zorgen, jouw gegevens worden “NIET” gedeeld met anderen!
Voeg je bij 33K andere abonneesDankjewel aan iedereen die de tijd neemt om ons te laten weten dat ons werk hen raakt. Dankjewel voor de warmte, de steun en de verbondenheid. Dankjewel dat jullie onze blog niet alleen lezen, maar ook mee vormgeven door jullie reacties.
Samen maken we van deze plek een hartelijke, eerlijke en inspirerende online thuis. En dat is misschien wel het mooiste compliment dat we kunnen krijgen.
Warme groet uit Tienen, Theo‑Herbots 💙📚 Blogger met Hart & Ziel
P.S. Nu u toch hier bent…
💬 Laat gerust een reactie achter onderaan dit bericht. Ik lees graag uw mening, ervaringen of aanvullingen.
🌐 Neem ook eens een kijkje op mijn sociale media via de links hieronder. Daar deel ik regelmatig nieuwe inzichten, tips, handelsideeën en updates.
🔄 Vond u dit bericht nuttig of interessant? Help dan mee om deze informatie te verspreiden en deel het verder via de sociale media-deelknoppen onderaan deze pagina.
🙏 Alvast bedankt voor uw bezoek, uw reactie en het delen. Samen bereiken we meer mensen die er hun voordeel mee kunnen doen!
✨ Veel leesplezier en graag tot binnenkort! 🚀
📱 Goed nieuws! Vanaf nu zijn wij ook bereikbaar via WhatsApp. 🎉
Heb je een vraag over mijn blog, een blogbericht of één van de diensten die ik aanbied? Dan mag je mij gerust een WhatsApp-bericht sturen. 😊
⚠️ Belangrijk: dit WhatsApp-kanaal is uitsluitend bedoeld voor vragen over mijn blog en mijn diensten. Reclameboodschappen, commerciële aanbiedingen en spamberichten worden niet beantwoord.
💬 Ik help je graag verder met al je vragen!
Chat op WhatsAppTheo Herbots
🌟📸 Blogger & Fotograaf uit Tienen 💙Volg ons ook op Social-Media hier beneden👇
A cheerful creator invites viewers to follow, like, and share content in Dutch. Follow us on Social Media xfacebookinstagramyoutubepinterestlinkedinflickrtumblrvimeofoursquaremastodon #KerstmisKerstmenuKerstreceptenFeestdagenSamenGenietenTheoHerbotsTienen #TheoHerbots #TheoHerbotsFotografie #KerstmisChristmas #StepByStepChristmasMenu #TheoHerbotsTheVoiceFromTienen -
I write code. I did not expect to spend so much of my career thinking about
contracts.Three years ago my client agreement was two paragraphs in the body of an email.
It said what I'd build and what it cost. Every clause I've added since then went
in because something specific went wrong, and I'd rather you learn them from a
blog post than the way I did.Not legal advice — I'm a developer, not a lawyer. Have someone qualified in your
country read anything before you rely on it.1. Scope, with a "not included" list
The included list is the easy part. The not-included list is what saves you:
logo design, copywriting, photography, hosting fees, email migration, stock
images, ongoing maintenance.Clients don't read "not included" as hostile. They read it as someone who has
done this before.2. Payment in three parts
50% before work starts, 30% at design approval, 20% before launch.The deposit isn't a formality. It's the difference between a client who is
committed and a client who is exploring options.3. The deposit is non-refundable once work begins
You turned down other work to hold those weeks. That's what the deposit pays for.4. Late payment stops work
Not "may stop work". Stops. And the timeline moves by at least the length of the
delay — your calendar doesn't grow a free week later just because they were slow.5. What the client owes you, with actual dates
Content, logo files in vector format, hosting and domain access, feedback within
a set number of working days. Put real dates next to each one, in the proposal,
before anyone signs.6. The content delay clause
If I could keep only one clause, it would be this.If content is more than X days late, the project goes on hold, and the invoice
for work completed to that point becomes due. It rejoins my schedule when I have
room — which might be weeks later.This sounds harsh until the third time a project dies because nobody wrote the
About page. Almost every stalled project I've had stalled on content, not code.7. Revision rounds, and a definition of "round"
A round is one consolidated set of feedback. Five emails over three days is five
interruptions, not one round, and if you don't define it you will be the one
absorbing the difference.8. Change requests in writing, before any work
Client asks. You reply with cost and timeline impact. They confirm. Then you
start.This isn't bureaucracy, it's protection in both directions. They never get a
surprise invoice and you never do unpaid work. Small things I still absorb
without mentioning — the clause exists for the "while you're in there, can we
add a booking system" requests.9. Silence counts as approval
If I ask for sign-off and hear nothing for X working days after one reminder,
that stage is approved and we move on.Without this, one unresponsive client freezes your schedule indefinitely and
you have no way to restart it.10. Ownership transfers on final payment
Until the last invoice clears, the work is mine. The site goes live when payment
does.This is the single most effective clause for getting a final invoice paid, and
it has never once caused an argument with a client who intended to pay.11. One named decision-maker
When feedback arrives from four people who disagree with each other, someone on
the client's side has to resolve that before it reaches you. Name that person in
the contract.12. What happens if either side walks away
They pay for work completed. Anything prepaid and not yet worked against comes
back. Agreeing this while everyone is still friendly takes five minutes;
agreeing it afterwards takes a lawyer.None of this makes you difficult to work with. In my experience it does the
opposite — clients relax when the person building their site clearly knows how
projects go wrong, because it suggests you've finished a few.What's in your contract that isn't in mine? I'm still adding to this.#freelance #webdev #career #business #software #coding #development #engineering #inclusive #community
The contract clauses I added after three years of client websites -
Good morning. ☕🫖🍃
24 October 2026
Charlie and I spent part of the morning on the porch of my wife's little quilting shop. There was a welcome chill in the air, enough that I pulled on a sweatshirt before settling in with a Thermos of coffee. We enjoyed the quiet while waiting for the sun to climb above the trees in the east. The porch faces south, so during this time of year it catches the sunlight directly once the day gets underway.
Charlie wandered the yard, following scents and conducting his usual patrol until he had accomplished what he came outside to do. After that, he joined me on the porch, and together we watched the neighborhood slowly come to life.
Yesterday, we noticed a worker using a measuring wheel along the road out front. My curiosity got the better of me, so I walked over and asked what he was working on. He told me they were taking measurements for an AT&T fiber installation, which was welcome news. I've been hoping for AT&T Fiber to make its way here for several years, but until now it hasn't been available.
At the moment, I have AT&T Internet Air, a cellular-based internet service that works pretty well most of the time, but fiber should be a significant upgrade. I even let the crew stage several large rolls of fiber at the southeast corner of my property. They're supposed to begin work on Monday.
Now I'm debating whether to go with 1-gig service or splurge on the 5-gig plan. Honestly, 5 gigabits per second is probably far more than I need. But I've always been a bit of a computer geek, and there's something alluring about having more power than you can realistically use. It's kind of like needing nothing more than a sensible four-cylinder sedan but driving off the lot with a big Hemi under the hood instead.
"The sun shines not on us but in us."
― John Muir"The price of anything is the amount of life you exchange for it." ― Henry David Thoreau
#photo #photography #wildlife #nature #morning #seascape #technology #computers
-
AI can generate a financial model that looks coherent, contains valid formulas, and produces a plausible result while still being wrong in ways that matter.
A formula can reference the wrong cell. A cost assumption can be expressed in the wrong unit. A revenue schedule can omit a phase. A model can calculate correctly from an unsupported market assumption.
These are different failure modes, and they need different controls. For real estate feasibility models, the objective should not be to ask whether an AI-generated workbook looks correct. It should be to establish which properties can be tested automatically, which assumptions require evidence, and which decisions must remain with a qualified human reviewer.
A useful validation architecture has five layers:
- Structural validation
- Deterministic calculation checks
- Domain and consistency checks
- Evidence and provenance checks
- Human review and approval
No single layer is sufficient.
1. Separate the output from the evidence
Consider a hypothetical development model with the following inputs:- Site area and developable area
- Permitted gross floor area
- Unit mix or lettable area
- Revenue assumptions
- Construction and other development costs
- Financing assumptions
- Development programme
- Exit assumptions
The model calculates development costs, revenue, cash flows, residual land value (RLV), and potentially internal rate of return (IRR).
For example, a model might calculate an RLV of £4 million. That output can be mathematically consistent with the workbook and still be commercially misleading if the revenue assumptions are unsupported or the construction cost basis is outdated. Validation therefore needs to test both the calculation and the justification for its inputs.
2. Layer one: validate the structure before the numbers
Before reviewing financial logic, validate the shape of the generated output. If an AI system is expected to return structured data before creating a workbook, define an explicit contract. JSON Schema is one established option for specifying required fields, data types, and constraints.See the JSON Schema getting-started guide.
A simplified model input contract might look like this:
{
"project_id": "DEMO-001",
"currency": "GBP",
"site_area_sqm": 5000,
"gross_floor_area_sqm": 12000,
"construction_cost_per_sqm": 1800
}
This is illustrative data, not a market benchmark or a recommendation for a production schema.A structural validator could check that:
- Required fields are present.
- Numeric values are actually numeric.
- Areas and costs use declared units.
- Currency is explicitly identified.
- Values fall within defined technical bounds.
- Unexpected fields are rejected or handled deliberately.
- Missing values are not silently replaced with zero.
The last point is important. Zero and unknown are not equivalent. If a finance rate is missing, substituting zero can make a model appear more profitable. A missing value should normally trigger a validation error or an explicit unresolved status.
Structural validation establishes that the model can be interpreted. It does not establish that the model is economically sensible.
3. Layer two: use deterministic checks for deterministic rules
Rules that can be expressed precisely should not depend on an LLM's judgment. For example, if a model defines construction cost as gross floor area multiplied by construction cost per square metre, the expected calculation is:\text{GFA}
\times
\text{Cost per sqm}
]
For the hypothetical inputs above:
[
12{,}000 \times £1{,}800 = £21{,}600{,}000
]
A deterministic test can independently calculate the expected result and compare it with the workbook output.
from decimal import Decimalgfa_sqm = Decimal("12000")
cost_per_sqm = Decimal("1800")
reported_cost = Decimal("21600000")expected_cost = gfa_sqm * cost_per_sqm
assert expected_cost == reported_cost
This test checks arithmetic for the stated formula. It does not establish that the GFA is permitted, that the cost rate is appropriate, or that the formula captures every relevant cost.
A production implementation should also define tolerances where appropriate, particularly when comparing rounded spreadsheet values or calculations involving floating-point numbers.
Other deterministic checks might include:
Revenue equals the sum of its components.- Total costs reconcile to their component schedules.
- Cash flow totals reconcile across periods.
- Unit counts and areas reconcile between schedules.
- The reported output matches an independently calculated result.
- A sensitivity case actually changes the intended input.
- Required formula cells are not unexpectedly blank or replaced by constants.
Where possible, use independent calculations rather than simply checking that a formula cell contains a formula. A formula can exist and still be wrong.
4. Layer three: validate model relationships
Many serious errors are not syntax errors or arithmetic errors. They are inconsistencies between parts of the model.Suppose a development model contains:
- 120 residential units in the unit schedule
- 116 units in the sales schedule
- Revenue calculated using the sales schedule
- Construction costs calculated using the unit schedule
Every formula may evaluate successfully, but the workbook contains a discrepancy that needs resolution.
Domain-level checks can flag conditions such as:
- Unit counts that differ across schedules.
- Areas that exceed a declared model constraint.
- Revenue periods that do not align with the programme.
- Cost totals that exclude a populated cost category.
- An exit value that uses an inconsistent timing assumption.
- A sensitivity scenario that changes revenue but leaves dependent calculations unchanged.
- An IRR calculation using a cash-flow range that omits a period.
These checks should be encoded as explicit rules wherever the intended relationship is known.
Some rules require context. For example, whether a particular cost should be included in a development budget depends on the model's scope and conventions. A validator should not impose a universal rule where none exists.
Instead, it should identify the relevant condition, record the rule being applied, and send ambiguous cases for review.
5. Layer four: validate the provenance of assumptions
A financial model can pass every arithmetic test and still fail as an analytical tool.The reason is straightforward: calculations cannot establish the truth of their inputs.
For every material assumption, a validation system should try to preserve:
- The value and unit.
- The source or origin of the value.
- The source's date and relevant data period.
- The geography and asset type, where applicable.
- The transformation from source evidence to model assumption.
- Any manual adjustment made by the analyst.
- The model locations that depend on the assumption.
Consider a construction cost assumption of £1,800 per square metre. A validator might confirm that the figure is numeric, the unit is recorded, and the workbook uses it consistently. Those checks do not establish whether the figure is suitable for the location, asset type, specification, and cost period. That question requires appropriate evidence and professional interpretation.
An LLM may help extract candidate assumptions from documents or explain how a value is used in a workbook. The extracted result should still be checked against its source, and the resulting assumption should remain distinguishable from the underlying evidence.
A useful principle is:
Traceability makes an assumption inspectable. It does not make the assumption correct.6. Layer five: make human review a defined state transition
Human review should not be an informal final glance after an automated process has already treated the model as complete.A practical workflow can represent validation explicitly:
GENERATED
|
v
STRUCTURE_CHECKED
|
v
CALCULATIONS_CHECKED
|
v
DOMAIN_CHECKED
|
v
EVIDENCE_REVIEWED
|
v
HUMAN_APPROVAL_REQUIRED
|
+----> APPROVED FOR THE DEFINED PURPOSE
|
+----> RETURNED FOR CORRECTION
|
+----> BLOCKED: UNRESOLVED ISSUEThe states are illustrative, but the distinction matters. A successful automated test should not automatically mean that a model is approved. Approval should be scoped to a defined version of the workbook, its assumptions, its evidence, and its intended use.
A reviewer should be able to see:- What was generated.
- Which automated checks passed.
- Which checks failed or were skipped.
- Which assumptions lack adequate evidence.
- What changed after a correction.
- Who approved the model and for what purpose.
If a material input or formula changes after approval, the system should identify which checks need to run again and whether the earlier approval remains valid. This is where versioning and change tracking become part of model governance rather than administrative overhead.
7. Design the exception path before the success path
Validation is often designed around a clean example: the model is generated, every check passes, and the user receives the output. Production systems need to handle less convenient outcomes.A failed check should produce actionable information. “Validation failed” is less useful than “The unit count in the sales schedule differs from the unit schedule; review the linked inputs before approving revenue.”
Similarly, a warning should not disappear simply because a later stage of the workflow succeeds. For auditability, preserve the check identifier, the model version, the result, the relevant evidence, and the resolution.
8. Measure validation quality without inventing an accuracy score
A single “model accuracy” percentage can hide important distinctions. A workbook might pass every arithmetic test while containing several unsupported assumptions. Another may contain a harmless formatting issue but have fully reconciled calculations and well-documented inputs.A more useful validation report separates categories:
- Structural checks passed or failed.
- Deterministic calculation checks passed or failed.
- Domain checks passed, failed, or were not applicable.
- Assumptions with verified, missing, or conflicting evidence.
- Open exceptions and their severity.
- Human review status.
- The scope and version of the approved output.
If the system is evaluated over time, track false negatives and false positives for individual validation rules against a reviewed test set. Record the test cases, expected outcomes, rule versions, and known limitations.
Do not interpret a high pass rate as proof that the model is correct. It may simply mean that the checks cover only a narrow set of failure modes.
The purpose of validation is to make known risks visible and testable, not to manufacture certainty.
9. A practical implementation sequence
A team introducing validation around AI-generated financial models does not need to automate every review step at once.A sensible sequence is:
- Define the contract. Specify the required inputs, output fields, units, and missing-value behaviour.
- Write deterministic tests. Start with totals, reconciliations, formula ranges, and independent calculations.
- Add domain checks. Encode known cross-schedule relationships and clearly defined constraints.
- Track provenance. Associate material assumptions with sources, dates, units, and transformations.
- Introduce exception handling. Make failures explicit and prevent unresolved material issues from being silently treated as passed.
- Define human approval. Record the reviewer, workbook version, purpose, and outstanding qualifications.
- Build a regression suite. Retain representative valid and invalid examples and rerun the checks when the generation logic or validation rules change.
The test suite should include deliberate failures, not only successful examples. Examples might include missing finance assumptions, inconsistent unit counts, a formula referencing the wrong period, and a source whose geography does not match the project.
This helps test whether the validation process detects the intended problem rather than merely accepting a plausible-looking output.
Conclusion
Human-in-the-loop validation is not a person checking an AI result after the important work is finished. It is a system design in which deterministic rules handle deterministic questions, domain checks expose inconsistencies, evidence is kept separate from assumptions, and a human reviewer remains accountable for unresolved judgments.For financial modelling, that distinction is material. A workbook can be well-formed without being economically sound, mathematically consistent without being supported by market evidence, and ready for review without being ready for a decision.
The objective is not to make every AI-generated model look trustworthy. It is to make the model's logic, assumptions, limitations, and unresolved issues sufficiently visible that a professional can challenge it before relying on the result.#feasibility #realestate #ai #financial #software #coding #development #engineering #inclusive #community
Human-in-the-Loop Validation for AI-Generated Financial Models -
Charmy’s Army in “DEE SEAST – The Hell of the Ball” – Part 3: Blue Vests and Brown Bananas
<<< Previous COMIC strip NEXT COMIC STRIP >>>In the third installment of our saga, panic reaches a fever pitch before colliding directly with mundane retail logistics. Convinced that Walmart’s customer service desk has instituted a terrifying new policy for processing refunds, the ponytail girl spiraled into sheer dread: will returning a defective toaster get her tossed into a holding pen to be devoured by domesticated ghouls? Thankfully, the blonde clears the air. Dee isn’t eating dissatisfied shoppers; she works in the meat department devouring the expired cuts. She isn’t a mindless trash can, either—as corporate HR would insist, she is a proud “Waste Management Facilitator.”
The fluorescent lights of the retail district buzzed overhead like a hive of mechanical hornets. The ponytail girl stood dead in the center of the sidewalk, completely frozen in terror, clutching both hands to her face. Her eyes were practically the size of saucers, and her breathing sounded like a bellows working overtime.
“I bought a set of non-stick sauté pans three weeks ago,” she whispered, her voice trembling with sheer, unadulterated existential dread. “The coating is already flaking off near the handle. I have the receipt in my purse. I was literally planning to go to Customer Care this afternoon. But now? Now I know the truth! They’re going to look at my receipt, see that the packaging is torn, hit a discreet red button under the desk, and drop me down a trapdoor into Dee’s feeding pit!”
The blonde stared at her friend for three long seconds, an expression of profound exhaustion settling across her features. She pinched the bridge of her nose and let out a deep, shuddering sigh that blew a stray blonde lock out of her eyes.
“Have you ever, in your entire life, heard of a big-box store feeding actual human customers to an employee?” the blonde asked flatly. “Do you realize the liability insurance premiums on that alone? The Occupational Safety and Health Administration would have field inspectors crawling through the air ducts within forty-eight hours. The paperwork would take decades.”
“Corporations do terrible things to protect their quarterly profit margins!” the ponytail girl insisted, gesticulating wildly toward the towering blue sign visible above the tree line. “Think about it! Customer returns cost money! Salvage freight costs money! If you replace the return desk with an apex predator from beyond the grave, refund requests drop to absolute zero overnight! It’s the ultimate cost-cutting measure!”
“She’s in the meat department, you absolute lunatic,” the blonde barked, grabbing her friend by the arm and dragging her along the pavement. “She doesn’t eat dissatisfied patrons who lost their receipt for a shower curtain. She eats the brown ground chuck and the discount chicken thighs that have been sitting in the display cooler forty-eight hours past their sell-by date!”
The ponytail girl blinked once. Twice. Her frantic breathing slowed down, though the look of absolute disgust remained firmly plastered across her face. “Wait… what?”
“You heard Charmy earlier,” the blonde continued, shaking her head. “Food waste is one of the biggest logistical hurdles in supermarket management. Stores throw away literal tons of spoiled produce, dented cans, and graying beef every single calendar year. Landfills charge dumping fees. Commercial composters have strict guidelines. But an undead post-human? Their digestive systems—or whatever remaining chemical soup passes for an internal organ—can neutralize bacteria that would put a vulture into an intensive care unit.”
“So she’s a garbage disposal,” the ponytail girl summarized, wrinkling her nose until her freckles scrunched into a tight knot. “A glorified, walking, rotting kitchen sink drain with bangs.”
“Charmy said she prefers the title Waste Management Facilitator,” the blonde corrected with an ironic smirk. “Corporate America doesn’t hire monsters; they hire operational specialists. They probably gave her an orientation badge, a five-minute video on slips, trips, and falls, and a designated break room in the refrigerated storage annex so she doesn’t scare the bakery associates.”
Across the street, Charmy and Dee had paused outside a small convenience store. Dee was leaning against a lamppost, her head tilted at a precarious angle that suggested her neck vertebrae were merely suggestive guidelines. A passing delivery driver glanced at her, double-took, and quickly crossed the street with an expression of profound confusion, but nobody screamed. Nobody dialed the national guard. The world had simply absorbed the unthinkable and filed it away under routine municipal oddities.
“I don’t know what’s worse,” the ponytail girl muttered, watching Dee attempt to scratch her shoulder and nearly dislocating her collarbone in the process. “The idea that the zombie apocalypse ended with our society almost being overrun, or the idea that it ended with the survivors realizing zombies could be exploited for unpaid sanitation labor.”
“Welcome to late-stage capitalism,” the blonde replied with a dry chuckle. “If a catastrophic virus wipes out twenty percent of the population, the remaining eighty percent won’t mourn; they’ll just figure out how to put the fallen to work clearing out the dairy aisle. But hey, look at the bright side: at least Dee is earning an honest living. It’s more than half the guys you’ve dated this year can say.”
“That is a low blow and completely uncalled for,” the ponytail girl grumbled, though she couldn’t suppress a faint, cynical grin. “At least my exes showered once a week. Dee looks like she just crawled out of an abandoned septic tank behind a haunted waterpark.”
“True,” the blonde agreed, watching as Charmy gently handed Dee a small bottle of hand sanitizer, which she promptly attempted to drink before Charmy calmly redirected it to her palms. “She’s definitely rough around the edges. But that brings up an even more pressing dilemma: with Halloween coming up, what does an integrated undead citizen do for social life? And more importantly… what does this mean for the town dance?”
TO BE CONTINUED….
Rate this:
#books #fantasy #fiction #shortStory #writing -
Tokens Over Hires
In the middle of September I ran ccusage against every Claude Code session on my laptop since May. It walks the local logs, counts the tokens, and prices them at what the API would have charged. I expected a big number. What came back was about twenty billion tokens and just under fourteen thousand dollars, across every project I’d touched in four months, with most of it going to Pepper, which is now open for signups, so go check it out. Nineteen billion of those tokens were cached reads.
I sat with that for a minute. Fourteen thousand dollars is real money. At my current pace it works out to roughly thirty thousand a year. I could triple it and spend a hundred thousand dollars a year on tokens, and that still isn’t one engineer. In exchange, Chris and I have shipped more code than I’ve shipped in any stretch of my career. I wrote in September that the two of us merged 657 pull requests in our first thirty days with a budget instead of a platform team. When I put the ccusage number in those terms on a panel, it came to about a dollar fifty a pull request.
That number is what my laptop would have cost at API prices, and it isn’t what we actually pay. Here’s the whole bill for both of us. Two Codex subscriptions, one each, are $200 a month. Anthropic is $550 a month: a Max plan for me and Chris, plus two Vycari team seats, one for Chris and one that runs our automation. I have an Ollama subscription at $200 a year. Greptile is about $1,500 a month. All in, that’s a little under $2,300 a month, or about $28,000 a year, for both founders and every pipeline we run. It still isn’t one engineer.
The obvious conclusion is the one a friend reached when he heard the figure: if code is that cheap, just get more tokens. I thought so too, for about a day. Then I looked at what was actually slowing us down, and the token budget wasn’t on the list.
The Constraint Is Attention
Every agent I run needs things from me that tokens can’t buy. It needs a plan approved before it starts. It needs its pull request read when it finishes. When it hits something it can’t decide, it escalates, and somebody has to be there to answer. None of those steps is expensive on its own. The problem is what happens when I run enough agents that the steps overlap.
When I run too many agents, the cost goes up a little and the risk goes up a lot. The biggest thing that’s slipped past us so far was how we managed database connections. It got out of hand, a little at a time, while my attention was on other pull requests, and eventually it caused an outage. Chris had to roll forward while I was out of town, and I spent the following week building a proper database abstraction layer. He put it more bluntly than I would have: the thing that kills us is splitting our attention. That’s when stuff slips through.
When people ask how we decide what to spend, I give them the order. Optimize for human time, because that’s the scarcest thing we have. Then money, because that’s the second scarcest. Then everything around agent time. “I can waste agent time all day. I don’t care.”
So the number that limits us is how many agents one person can supervise well at the same time. I don’t have a precise figure for that ceiling. I know I’ve been over it, because I can feel the difference between a day when every pull request got a real read and a day when I was skimming to keep up.
Another friend told me recently about engineers at his company running up bills in the thousands to build simple internal copies of SaaS tools. His reluctant guess was that they just aren’t as good at using agents yet, and that it’s a skill people have to develop. I don’t know what they’re doing differently. It doesn’t sound like token maxxing, which I’ve never really understood either. I’d love to sit with engineers who run up giant bills and just watch. My guess is they’re using the agents inefficiently, and that what’s missing is supervision, which a bigger budget won’t fix.
Building for More Agents per Person
Almost everything I’ve built since the summer has been an attempt to raise that ceiling, and almost none of it has been about spending less.
The pipeline I described in The Agent That Never Merges is the first piece. Agents open pull requests continuously and never merge them, which means the supervision cost per pull request is bounded at one careful read. The pipeline absorbs the rest: triage, planning, the first round of review comments, the retries. I only see the work once it’s in a state worth my attention.
The second piece is where the work lives. I wrote about pulling Pepper apart into small, bounded repositories to keep CI fast and give agents less to load. It mattered just as much for my attention. An agent working in a repository with one job produces a pull request I can evaluate in one sitting.
We’re up to fourteen repositories now. Last week I moved our iOS app out of the monorepo into its own. That was 150,000 lines of code, and nobody noticed except Chris, who had to wait a day to land his next batch of iOS changes. Agents make refactors that size easy. Having the CLI and the iOS client in their own repositories also forces us to keep good API definitions between the server and its clients.
The third piece is delegation inside the agent layer itself. I run two Claude Opus 5.5 orchestrators on medium effort. One is the UTL, for uber tech lead, and its job is to spawn subagents that build features. The other is what I call the focused worker, and its job is working with me. It catches the manual tasks that come out of the UTL’s pull requests and keeps them in a ledger. Then we work through them together: systems changes, bringing up new platforms, migrating data, anything that needs my level of access and oversight. Everything else goes to a subagent under the UTL, Opus for design docs and code reviews, Sonnet for implementing a feature from a design doc. Every one of these agents can consult a model a tier above it as an advisor, and they all share a wiki for notes.
Anthropic is now advertising much the same pattern with Claude Projects, and I’m happy to see others arriving at the same answer. Chris has been building a loop that babysits open pull requests through review until they score well enough to be worth a human’s time. Each layer like that turns a job I used to do by hand into something I check. The ceiling goes up one delegated task at a time.
The Token Budget Was the Easy Problem
There was a week in September when the meter really was the constraint. We ran through our free credits and paid about $120 in overage. Then AutoDev ate the whole Vycari quota, and I did server cleanup by hand because I couldn’t do anything else.
Most of that was self-inflicted. I’d started with Fable as the orchestrator, with no cap on context, and burned a week’s quota in three days. The setup above fixed it. The orchestrators run on medium effort, and the cheaper model does the implementing. Opus answers the reviews because Sonnet is too literal about them, and a literal reading turns two review cycles into twelve. Every agent auto-compacts at 200K tokens, because Anthropic charges more for context past that point. With that setup, and the work spread across parallel sessions, I find it hard to spend all of my quota. My goal now is to hit 99% of it every week just before it resets. I keep a list of research projects, and if I have quota left 24 hours before the reset, I spin one up. That isn’t the same as maxing out tokens. I’m not trying to use as many as possible. I’m trying to use all the ones I’ve already paid for.
There’s also a second account on the same machine. Claude Code reads a
CLAUDE_CONFIG_DIRenvironment variable, so two shells with two config directories give you two accounts side by side. The second one runs the AutoDev and code review pipelines, and those use up its quota every week, so it isn’t a fallback for my own sessions. When I do run short, I supplement with other labs’ plans. Every one of those fixes took an afternoon or less. None of the supervision problems above has had an afternoon fix.Where the Money Actually Goes
While I had the numbers in front of me, I looked at where development spend actually lands, because it isn’t where I expected either.
Development tokens currently run about ten times what the product itself consumes, even with real people using it. Building the thing costs more than running it. That won’t last. The feedback from our private beta has been really good, and we now open Pepper to a limited number of new signups every day, so product usage is rising quickly.
Most of what we actually pay goes to code review. Subscriptions are the cheap way to buy tokens if you’re willing to hit limits, so they’re the smaller line. Greptile reviews every pull request we open, and at about $1,500 a month it’s our biggest single expense. We both think it’s worth it, because it’s the layer that lets the never-merge pipeline run without me reading every first draft.
In October I tested that. I spent a few days building a cheaper reviewer to replace it. I came out the other side saying, “I think we should just pay for it because I can’t do it cheaper.” What I could change was how often we call it. The agents kept asking for a re-review before they’d fixed anything. Because every repository shares a common dev environment, the fix went in once: our pull-request skill now has agents run
/simplifyand then/code-reviewbefore they’re allowed to open a pull request. On many of our repositories, our own reviewer also does the first round and only then calls Greptile. My goal is a pipeline where Greptile’s reviews come back with nothing to say. We’re not there yet, but we get a little better every week.I’d rather pay for review than have a second person do it, and the reason isn’t salary. The person would need supervising too, because review is a job I’d have to check, not one I can hand off.
What a Hire Is For Now
Five years ago, if I’d been getting a product like this ready for market, I’d have been hiring twenty to fifty engineers. The work would have needed that many hands, and most of what they’d have done was write code. Today the code is the cheap part. If I bring someone in to write code, I’ve added a person who needs plans approved and pull requests read, which is the exact resource I’m short on. A hire whose job is output adds coordination faster than it adds capacity.
I said on a podcast that came out last week that the code I’ve written would have cost about fifteen thousand dollars at API prices, and that I couldn’t hire engineers for that money. That’s true. The engineers I’d still want are a different kind from the ones I hired at Google. We need a few more people who can herd agents, not fifty.
The engineering hire that adds capacity is a different shape. It’s someone who can own a bounded service whole. Here’s the interface, here’s everything it needs to do, let me know when it’s done. That person brings their own supervision. They run their own agents, read their own pull requests, and answer their own escalations, and the only thing that crosses the boundary between us is the contract. Supervision divides along the interface instead of piling up on one person. That’s a tech lead’s job, and it’s the only kind of engineering hire I can see that raises the ceiling instead of lengthening the queue.
That raises a fair question about how anyone grows into that job now, which I tried to answer in The Questions Are the Job. The other advice I give is to work on open source. I’ve met people who showed they could work really efficiently with agents through open source projects, Gemini CLI in particular, and some of them ended up being hired onto my teams. Open source has its own problems right now. But if you show up as a thoughtful engineer with features or bug fixes that are well reviewed, well tested, and bring value to the project, I think you’ll be welcome. That’s one of the reasons I decided to open source the Pepper CLI.
The first hire probably isn’t an engineer at all. I’ve said this a few times now, including on stage at a panel in September. Neither Chris nor I are go-to-market people, and I may hire one before I hire another engineer. I can create piles and piles of code, even relatively good code. What I can’t do is agentically acquire customers. (Did I mention that Pepper is open for signups now?) Someone in marketing came up after the panel and told me I’d validated her existence.
The Third Trend
I’ve watched this happen twice before. Open source developer tooling made it so a small team didn’t need to buy or build its own compilers, databases, and frameworks. Cloud infrastructure made it so that team didn’t need to own hardware or a data center. Each time, the number of people you needed to start something real dropped, and the skills that mattered shifted toward the people who understood systems well enough to compose what was suddenly free.
Agentic tools are the third one. Anyone with a good idea can now get from concept to production on a budget that would have been a rounding error in a Google planning cycle. But the constraint didn’t vanish. It moved, the same way it did the last two times, toward the people who understand systems design well enough to drive the agents and notice when something has slipped through. I wrote a year ago that management skills were going to carry over to working with agents. I didn’t expect to be proving it with a two-person org chart and fourteen thousand dollars of tokens.
This isn’t only a small-company problem. At Google it was hard to get more than a few changes in a day, because each one waited on code review. I’ve talked to engineers there who now do all their work in experimental directories that don’t require review, then port it back to their team’s repository at a pace the review process can keep up with. That’s what happens when you don’t manage for human attention. Productive people spend their cycles waiting on the process.
When other companies ask me what to change, my answer has become: drive until human attention is the scarce resource, then build for that. If you’re reading your own ccusage number and wondering whether the answer is more tokens, look at where your attention went first. For us the answer has been more interfaces. Those are the places where one person’s supervision ends and another’s begins, or where an agent takes over a job one of us used to do by hand.
#Agents #AI #Developer #Startups -
*Manchester dates* for The Crucified Silence – Sunday November 22nd – Irish World Heritage Centre. 6pm.
“A story anyone can relate to…” — Irish Independent
Click here to secure your ticket now!
About
Following acclaimed performances in Athlone, Castlebar, Ballinrobe and Galway, The Crucified Silence comes to Manchester on Sunday 22nd November at 6pm, bringing a distinctive voice from the West of Ireland to the iconic Irish World Heritage Centre.
Hilarious, heartbreaking and brimming with dark Irish humour, The Crucified Silence is a compelling one-man play written and performed by acclaimed Irish playwright Mick Donnellan. Set in Ballinrobe, Co. Mayo, the story follows Joe, a local guard who has crossed a line after a volatile altercation with his superintendent. As he drinks his way around town, he conjures vivid, nostalgic images of familiar landmarks and meeting places, including The Bowers walk, Art O’Neill’s Bar and Geoff’s pub. These recollections bring his world to life, drawing audiences into a community shaped by its own rhythms, rituals and relationships.
Yet beneath the laughter lies a deeply moving story of loneliness, loss, regret and the search for connection. Just as Joe’s sharp wit and comic observations have audiences laughing, glimpses of his troubled past reveal a more vulnerable man struggling to come to terms with the life he has lost. The result is a play that can have you laughing out loud one moment and breaking your heart the next.
Populated by recognisable Irish characters and brought vividly to life through authentic Irish dialect, cultural nuances and a rich tradition of storytelling, the play offers a compelling glimpse into the humour, warmth and complexities of everyday life in rural Ireland. For those familiar with Irish life, there is much to recognise; for those discovering it for the first time, an opportunity to experience a distinctive culture through characters who feel wonderfully real.
The Venue
A much-loved hub for Irish culture, arts and community in the North West of England, the Irish World Heritage Centre provides a fitting setting for a play that celebrates Irish storytelling while exploring experiences that transcend borders and backgrounds.
For Manchester’s Irish community, the evening offers a powerful sense of home, evoking the people, places, humour and shared experiences that connect us to where we come from. It is also a wonderful opportunity to celebrate the strength of Irish theatre and the remarkable stories being created in Ireland and finding audiences beyond its shores.
Universal Appeal
Although Joe’s world may be rooted in a small town in Co. Mayo, his struggles are universal. His attempts to make sense of a life shaped by difficult choices, personal loss and fading connections will resonate with anyone, from all cultures and backgrounds, who has ever looked back on their past and wondered how things might have turned out differently.
With minimal staging and intimate, uncompromising storytelling, the play places audiences face to face with Joe’s inner world, where humour becomes a defence against pain and silence can speak louder than words. Mick Donnellan’s powerful central performance draws audiences towards a devastating climax, balancing theatrical intensity with the feeling of a deeply personal confession.
All are welcome to join for an evening of big laughs, poignant storytelling, heartbreaking moments and an unforgettable injection of high-quality theatre!
Spaces limited so be sure to secure your seat as early as possible :)
About Mick Donnellan and Truman Town
Mick Donnellan works as a successful Playwright, Novelist and Screenwriter. Film credits include Tiger Raid adapted from Mick’s Play Radio Luxembourg. Optioned by London Film Company Dixon/Baxi/Evans, the script was developed in London and shot in Jordan. Starring Brian Gleeson, Damian Molony and Sofia Boutella, it was accepted into the Tribeca film festival (New York) and was also seen at Cannes and Edinburgh.
The Irish Premiere was screened at the Galway Film Fleadh and you can watch the Tiger Raid trailer here.
Mick is the author of six novels:
Recent Work:
Mick Donnellan has had two major theatre productions hit the stage in 2025.
Outlaw Pete premiered at the Town Hall Studio, Galway in April 2025, starring Laura Hutchinson, Brian Cahill, and Carl Jones. Following its debut, the production toured to the Linenhall Arts Centre in Castlebar in May, before returning to Galway for the Galway Fringe Festival in July, where it sold out Kennedy’s Bar on Eyre Square.
Donnellan’s second new play of 2025, Class of ’57, was produced by Athlone Little Theatre and directed by Caroline Coyle, featuring standout performances from Ellen Ryan, Brian Toolan, and Nino Magilocco.
In December 2024, his most recent book Galway Blues was published to great acclaim. He received the Mayo Theatre Bursary through Mayo Arts Office in April the same year.
Prior to that, he was awarded the Agility Award through the Arts Council of Ireland and his play Nally was supported by Westmeath Arts Office.
In other theatre work, The Crucified Silence (as a short play) was chosen as part of the Scripts Ireland Play festival. After a week of intensive workshops with Playwright Eugene O’Brien, the monologue was directed by Jim Culleton (Fishamble) and performed by Aaron Monaghan. Following this, Mick took part in the Galway Theatre Development Programme, run by Andrew Flynn in conjunction with Galway’s Town Hall Theatre, which resulted in a residency at the Tyrone Guthrie Centre.
His other plays include Sunday Morning Coming Down, Shortcut to Hallelujah, Gun Metal Grey, and Velvet Revolution.
He is listed on the Irish theatre institute here: http://irishplayography.com/person.aspx?personid=47564
About Truman Town:
Truman Town Theatre exploded on to the theatrical circuit with their Play – Sunday Morning Coming Down. Written and directed by the company’s Artistic Director Mick Donnellan, it immediately sold out the Galway Town Hall Studio for five nights on the first run. Following that, the crew went on tour to Mayo, selling out Lisloughrey Lodge, Cong,The Valkenburg Niteclub, Ballinrobe and the Linenhall in Castlebar. It also enjoyed large audiences on the Main Stage on Galway’s Town Hall and went on a National Tour covering – Glor Ennis, St. John’s Listowel, Cork Arts Theatre and it sold out five nights at The New Theatre, Dublin. It was also performed by DRUID as a public reading during the Galway Arts Festival.
Truman Town followed this phenomenal success with a second Play – Shortcut to Hallelujah. Again, written and directed by Mick Donnellan, it deals with the curse on the Mayo football team. It sold out the Town Hall Studio, went on tour to Ballinrobe and the Linenhall in Castlebar and then down to St. John’s Theatre, Listowel Co. Kerry where it was requested back to headline Friday night of Listowel Writer’s week.
Between this, a third drama was produced as part of the Galway Theatre Festival. It was titled Gun Metal Grey.
Shortcut to Hallelujah returned from Listowel Writer’s Week to perform on the Main Stage Galway for a wildly successful five nights after which Velvet Revolution, the fourth Truman Town production, also written by Mick Donnellan, was premiered in St. John’s Theatre, Listowel. It went on tour to Kilmallock, Kenmare and Waterville, then up to Ballinrobe, on to Galway and ran for ten days as part of the Galway Fringe. Mentioned as a Highlight of the festival by the Irish times, it was subsequently performed in Campbell’s Tavern, Cloghanover, Headford, Electric Picnic and The New Theatre, Temple Bar, Dublin.
Radio Luxembourg, Mick’s fifth Play, was bought by a London Film Company (Dixon/Baxi/Evans) and has been adapted for the screen. The title for the movie version is “Tiger Raid”. Starring Brian Gleeson, Damian Molony and Sofia Boutella, it was accepted into the Tribeca film festival (New York) and was seen at Cannes and Edinburgh. The Irish Premiere was screened at the Galway Film Fleadh.
Currently Mick is working on the exciting screen adaptation of Shortcut to Hallelujah with Florence Films. The screenplay is titled Sam and is based around the curse supposedly put on the Mayo Football team as they returned home as All Ireland Champions in 1951. Drenched in Irish lyricism and modern day dark humour, the script has been met with keen interest by film producers and actors throughout the industry.
Between writing projects, Mick has enjoyed roles as a lecturer in writing at University of Ireland and TUS Athlone.
*
Read more on www.mickdonnellan.com
#books #music #news #Poetry #writing -
Pest control businesses manage more than inspections and treatments. Every service visit involves appointment scheduling, technician coordination, travel planning, customer communication, and recordkeeping.
As a company grows, these administrative responsibilities become increasingly difficult to manage through spreadsheets, phone calls, and disconnected software.
Artificial intelligence (AI) and workflow automation offer new ways to organize these processes. However, their value depends on how well they solve real operational problems.
This article examines five areas where AI and automation can support pest control businesses, along with the technical considerations companies should evaluate before adopting new systems.
- Smarter Appointment Scheduling
Traditional appointment scheduling often requires office staff to coordinate technician availability, customer preferences, service duration, and travel distances manually.
Scheduling software can automate several parts of this process.
For example, a scheduling system might:
Display available appointment windows based on technician calendars.
Assign jobs according to service area and technician availability.
Send automated appointment confirmations.
Notify customers when appointments change.
Identify scheduling conflicts before bookings are finalized.
AI-assisted scheduling can go further by analyzing historical job durations and recommending suitable appointment windows.
However, these recommendations are only as reliable as the underlying data.
A business with inaccurate service durations or incomplete technician availability records may still experience scheduling problems, even after introducing automation.
Technical consideration: Look for scheduling systems that support configurable service durations, technician constraints, calendar integrations, and manual overrides.
- Route Optimization for Field Technicians
Travel time is a significant operational consideration for businesses that send technicians to multiple customer locations each day.
Basic route planning can arrange appointments geographically. More advanced optimization systems consider additional constraints, including:
Appointment time windows
Technician starting locations
Estimated travel times
Service duration
Technician skills and availability
Vehicle capacity or equipment requirements
Some systems use optimization algorithms to recommend more efficient visit sequences.
AI-based prediction may also help estimate travel times or anticipate schedule disruptions.
Consider a technician assigned six appointments across different neighborhoods.
A poorly organized schedule might require unnecessary backtracking. A routing system can evaluate possible visit sequences and recommend an order that better satisfies the day's constraints.
Importantly, route optimization is not automatically AI. Many useful routing systems rely on established mathematical optimization methods rather than machine learning.
For pest control companies, the practical question is whether the system produces workable routes while respecting real service requirements.
- CRM Automation and Customer Communication
Customer relationship management (CRM) systems help businesses organize customer information, service histories, recurring treatments, and communication records.
Automation can reduce repetitive administrative work.
For example, a completed service appointment might trigger the following workflow:
The technician marks the job as completed.
The system updates the customer's service history.
A service summary becomes available.
The customer receives a completion notification.
The system schedules a future reminder when appropriate.
This workflow does not necessarily require generative AI. Many CRM platforms support rule-based automation using triggers, conditions, and actions.
AI may provide additional capabilities, such as summarizing customer interactions or categorizing incoming service requests.
Nevertheless, businesses should review AI-generated information before using it in sensitive customer communications or treatment documentation.
Technical consideration: Evaluate how the CRM handles customer consent, communication preferences, recurring service records, and data access permissions.
- Connecting Software Through APIs and Integrations
One of the most useful opportunities for pest control technology is connecting systems that would otherwise operate independently.
A business might use separate applications for:
Website inquiries
Customer management
Appointment scheduling
Technician dispatch
Invoicing and payments
Reporting and analytics
Without integrations, employees may need to enter the same information into multiple systems.
Application programming interfaces (APIs) allow software applications to exchange information through defined interfaces.
For example, an integration could connect an online booking form with a field service management platform.
When a customer submits a booking request, the integration might create a customer record, generate a service request, and notify office staff.
A typical architecture could look like this:
Website Booking Form
|
v
API / Integration Layer
|
v
Field Service Management System
|
+--> Customer Record
|
+--> Service Request
|
+--> Scheduling Queue
|
+--> Notification WorkflowFor developers implementing these integrations, several considerations matter:
Authentication: API access should use secure authentication mechanisms and appropriately scoped credentials.
Validation: Incoming booking data should be checked before records are created.
Duplicate prevention: Retry requests should not accidentally create duplicate customers or jobs.
Error handling: Failed integrations should be logged and retried safely.
Privacy: Customer addresses, contact details, and service records should be handled according to applicable privacy requirements.
Before purchasing software, businesses should investigate whether the vendor offers documented APIs, webhooks, native integrations, or supported third-party automation tools.
- AI-Assisted Reporting and Business Analysis
Pest control businesses generate operational data through appointments, service records, customer interactions, and invoices.
Reporting tools can organize this information into useful business metrics.
Examples include:
Completed appointments per technician
Average time spent on service visits
Appointment cancellations
Recurring service activity
Travel time between appointments
Outstanding invoices
AI-assisted analysis may help identify patterns or generate plain-language summaries of reporting data.
For example, a system might highlight an increase in rescheduled appointments or identify service areas with unusually long travel times.
However, AI-generated summaries should be checked against the original records.
A useful reporting system should allow managers to trace a recommendation or observation back to the underlying data.
- What Should Businesses Evaluate Before Adopting AI?
Adding AI features does not automatically make a software platform better.
Before investing, pest control businesses should ask several questions.
Does the software solve a specific operational problem?
Start with a measurable issue, such as missed appointments, repetitive data entry, or inefficient dispatching.
Can employees understand and override automated decisions?
Technicians and dispatchers need practical ways to correct schedules and handle unexpected circumstances.
Does the system integrate with existing tools?
A platform that creates additional manual data entry may undermine the intended benefits.
How is customer information protected?
Review data access controls, retention policies, vendor agreements, and security practices.
How will performance be measured?
Establish a baseline before implementation. Compare outcomes such as scheduling errors, administrative time, or travel efficiency after deployment.
Businesses should also distinguish between genuinely useful AI capabilities and conventional automation presented with AI-focused marketing language.
- A Practical Implementation Approach
For smaller pest control businesses, introducing several new systems simultaneously can create unnecessary complexity.
A more manageable approach is to implement technology in stages.
Stage 1: Document existing workflows. Identify how appointments, service records, and customer communications are currently handled.
Stage 2: Select one problem to address. For example, automate appointment confirmations before attempting a complete dispatch-system replacement.
Stage 3: Test with a limited group. Introduce the workflow to a small team and document errors, exceptions, and employee feedback.
Stage 4: Measure results. Compare the new process against the previous workflow using consistent metrics.
Stage 5: Expand carefully. Introduce additional integrations or AI-assisted features only when the earlier implementation is functioning reliably.
This approach makes it easier to identify which technologies provide practical benefits.
Conclusion
AI and automation are expanding the options available to pest control businesses, particularly in scheduling, route planning, CRM workflows, software integrations, and reporting.
The most effective systems are not necessarily those advertising the largest number of AI features.
They are the systems that support reliable operations, provide useful information, integrate with existing workflows, and allow employees to remain in control of important decisions.
For independent research into pest control software, scheduling tools, CRM platforms, and technology comparisons, explore Pest Tech Research.
Better Technology. Stronger Pest Control.#automation #ai #software #api #coding #development #engineering #inclusive #community
How AI and Automation Are Changing Pest Control Business Operations -
DATE: October 25, 2026 at 06:00AM
SOURCE: PSYPOST.ORG** Research quality varies widely from fantastic to small exploratory studies. Please check research methods when conclusions are very important to you. **
-------------------------------------------------TITLE: Your body makes its own cannabis-like chemicals as you run, and neuroscience research finds they keep rising all the way to the marathon finish line, a possible clue to the runner’s high
A long run appears to keep the body’s own cannabis-like chemical messengers active for hours. New research published in BMC Medicine indicates that one of these compounds, anandamide, climbs steadily during a marathon and stays elevated 45 minutes after the finish, and that levels are also higher after ultramarathons of up to 230 kilometers. These chemical changes occurred alongside shifts in mood, such as reduced anxiety after running, although the study did not test whether one caused the other.
The runner’s high is a state some people report during or after endurance exercise, marked by euphoria, reduced anxiety, less pain, and a sense of calm afterward. Early explanations credited endorphins, the body’s natural opioid painkillers, but endorphins are large, water-soluble molecules, and there is no convincing evidence that they cross the blood-brain barrier, the protective filter between the bloodstream and the brain, in meaningful amounts.
Endocannabinoids offer an alternative: they are small, fat-soluble molecules made on demand from cell membranes, they can cross that barrier, and they act on the same cannabinoid receptors targeted by THC, the main psychoactive compound in cannabis. The two best studied are anandamide and 2-arachidonoylglycerol, often shortened to 2-AG.
Laboratory experiments began supporting this shift in thinking when a 2015 animal experiment led by Johannes Fuss, the senior author of the new study, showed that wheel-running mice relied on cannabinoid receptors, rather than opioid receptors, to experience reduced anxiety and lower pain sensitivity. Human research soon followed, including a 2021 clinical trial by the same group where researchers gave participants a medication that blocked opioid receptors. The runners still reported the typical calm and euphoric sensations of a runner’s high, suggesting that endorphins were not required for those effects.
In a 2022 systematic review, the same group found that 14 of 17 studies detected a rise in endocannabinoids after a single bout of exercise. But as the authors of the new study note, nearly all of that human research involved workouts lasting under an hour, leaving open what happens during true long-distance events.
“Humans are capable of running for many hours, sometimes even days, and we wanted to understand what happens to the endocannabinoid system during such extraordinary endurance efforts,” lead author Michael Siebers, a psychiatrist at LVR University Hospital Essen, told PsyPost.
“I believe that our ability to run long distances cannot be explained by anatomy alone,” Siebers explained. “We probably also need an entire orchestra of neuromodulators that reward us for sustained physical activity and help us continue running despite fatigue and discomfort. Thanks to a wonderful collaboration with researchers from Ulm and the German Sport University Cologne, we were able to investigate these processes during marathon and ultramarathon running, including distances of up to 230 kilometers.”
To investigate these biochemical and emotional shifts under real-world conditions, Siebers and his colleagues, including senior author Johannes Fuss of the University of Duisburg-Essen and collaborators at University Hospital Ulm and the German Sport University Cologne, designed two field studies of trained endurance athletes.
The first investigation examined 19 experienced runners, including seven women and 12 men, who completed a marathon course consisting of three 14-kilometer loops around Lake Baldeney in Essen, Germany. To establish a realistic comparison, each runner returned one to two months later to complete an identical-duration walking session along the same route at their preferred pace. Blood samples were drawn at the start, at the 14-kilometer and 28-kilometer marks, immediately after the full course (about 43 kilometers), and after a 45-minute rest period. Alongside blood draws, participants completed visual rating scales to score their current levels of euphoria, anxiety, and physical pain.
The second investigation followed 36 athletes (16 ran 100 kilometers, 7 ran 160, and 13 ran 230) taking part in the TorTour de Ruhr, a non-stop ultramarathon in central Germany. These athletes, comprising 13 women and 23 men, provided blood samples and mood ratings before the race and shortly after crossing the finish line. In both studies, laboratory technicians measured several key lipids, including anandamide and 2-AG.
In the marathon study, levels of anandamide rose progressively across the entire run. By the mid-race mark, anandamide was higher during running than during walking, which produced only modest changes, and it remained higher 45 minutes after the marathon ended. Running was also far more intense, with runners averaging about 83 percent of their estimated maximum heart rate, compared with about 58 percent while walking. The compound 2-AG displayed a different trajectory, showing lower levels early in the run compared to walking, but climbing during the final kilometers and staying elevated during early recovery.
The ultramarathon runners exhibited similar biochemical patterns upon completing their races. Anandamide and 2-AG concentrations were both higher after the race across all three ultramarathon distances compared to pre-race baselines. In an exploratory comparison, post-race anandamide levels after the marathon were nearly double those seen after the ultramarathons (32.4 versus 17.1 in the study’s measurements), which the authors suggest may reflect the higher running intensity of the shorter race.
Mood ratings also shifted during running. Marathon participants reported higher euphoria while running than while walking at several points, although at the 28-kilometer mark, a stage where runners often describe “hitting the wall,” euphoria was no longer different from walking. Anxiety ratings started slightly higher before the marathon than before the walk, then fell toward the end of the run, and pain ratings showed little change after 14 kilometers but rose markedly from 28 kilometers on. In the ultramarathon group, anxiety decreased after the race, more so at 100 and 160 kilometers than at 230, while pain rose and euphoria did not change in a statistically significant way.
When asked afterward, only 3 of the 19 marathoners said they had experienced a runner’s high during the marathon, while 8 said they had not and 8 were unsure; among the ultramarathoners, 12 said they had and 19 said they had not.
The findings are in line with research covered by PsyPost in 2022, which found that acute exercise consistently increased endocannabinoid levels, especially anandamide, with moderate intensity yielding stronger boosts than low intensity.
“This is an interesting study, particularly because it’s not easy to investigate physiological responses to exercise over marathon and ultramarathon distances,” said Danielle McCartney, a research affiliate at the University of Sydney who was not involved in the study. “The key finding is that circulating concentrations of anandamide (AEA), an endocannabinoid, increased progressively throughout the marathon and were also elevated following ultramarathons of 100, 160 and 230 km.”
“Previous studies have consistently shown that moderate-intensity running increases blood concentrations of AEA,” McCartney told PsyPost. “However, most of this research has focused on relatively short bouts of exercise (less than 60 minutes). This study fills an important gap by examining much longer running distances, and shows that increases in AEA also occur during marathon and ultramarathon running.”
The researchers see the sustained activity as a possible clue to how humans manage hours of running.
“One of our most important findings is that the body’s own cannabinoid system remains active even during extremely prolonged exercise,” Siebers noted. “We observed substantial increases in endocannabinoids, particularly anandamide, not only during marathon running but also after ultramarathons lasting many hours.”
“These molecules are sometimes described as the body’s own cannabis-like substances because they act on the same cannabinoid receptor system targeted by THC,” he said. “They may contribute to the rewarding, calming, and potentially pain-modulating effects of running. From an evolutionary perspective, I find this particularly fascinating. Humans have an extraordinary capacity for endurance running, and the endocannabinoid system may be one of the biological mechanisms that make prolonged running not only physically possible but also psychologically rewarding.”
Siebers described the shift many runners report over the course of a run.
“At the beginning of a run, everything may feel uncomfortable,” he observed. “Your calves are aching, your back feels stiff, and every step requires some effort.”
“But after a while, something can change,” he noted. “Your movements become smoother, running feels increasingly effortless, and you may enter a state of flow. Sometimes this develops into euphoria, while everyday worries and stress seem to fade into the background.”
Siebers also sees potential relevance for mental health.
“As a psychiatrist, I find this especially interesting because running can become a valuable tool for coping with stress, improving mood, and supporting mental well-being,” he added. “Of course, exercise is not a replacement for professional treatment when it is needed, but for some people, it can be an important part of their recovery and everyday life.”
The study did not test whether runners whose anandamide rose the most felt the most euphoric or calm.
McCartney cautioned, however, against assuming that these chemical increases directly generate the emotional sensations reported by participants. “It’s important to recognize that this study doesn’t establish that increases in AEA are responsible for the ‘runner’s high,'” she explained. “It shows that prolonged running increases blood AEA concentrations and is associated with changes in mood, including increased euphoria and reduced anxiety. While these findings are consistent with the idea that AEA contributes to the runner’s high, they don’t establish a causal relationship.”
The TorTour de Ruhr presented extreme physical demands, requiring runners to navigate unfamiliar routes for up to 230 kilometers, often through the night and in isolation.
“What impressed me most was witnessing what humans are capable of achieving,” Siebers recounted. “Some of our participants ran distances of up to 230 kilometers, maintaining their effort for many hours, sometimes running alone through the night on unfamiliar trails. Equally fascinating was the atmosphere among the ultramarathon runners. Despite the enormous physical demands, there was a remarkable sense of community and positivity.”
“I was particularly struck by participants who reported very little anxiety after these extraordinary distances, even after spending hours alone in unfamiliar surroundings,” he said. “Some runners also reported surprisingly little pain despite covering distances that would seem almost unimaginable to most people. These observations make me wonder how strongly our internal neuromodulatory systems can influence the way we experience physical effort, pain, and fear.”
Pain was still common: 29 of the 36 ultramarathoners reported pain during the race, only five reported none, and eight said they used pain medication, particularly in the longest race.
As with all research, there are some caveats to consider. The marathon study used walking as a comparison rather than having participants sit quietly, meaning the control condition still involved mild physical exertion. Participants also selected their own running and walking speeds, which preserved a realistic race environment but introduced variation in how hard each individual was working.
“I have reasonable confidence in the main findings, particularly because the increases in AEA were consistent across the marathon and ultramarathon studies and align with previous research,” McCartney told PsyPost. “However, there are some limitations worth considering. Measuring endocannabinoids in blood can be technically challenging, and although the authors used established analytical methods, they don’t explicitly report whether these methods were validated.”
“I’d also have liked more information about what participants ate during and after exercise,” McCartney added. “We know that nutrient intake can influence blood AEA concentrations, so it’s possible that dietary behavior affected the measures.”
The authors describe their laboratory analysis as following established, standardized protocols, including adding chemically labeled reference versions of each compound to every sample to allow exact measurement. They also acknowledge that participants’ nutrition, rest, and time of day were not fully controlled.
Every participant also ran the marathon before doing the walking session, which the authors note may have raised anxiety at the start of the running day. The samples were also small, with 19 marathoners and between 7 and 16 runners at each ultramarathon distance, and no blood was drawn during the ultramarathons themselves.
The emotional measures relied on brief, single-item rating scales, which capture only a snapshot of complex mental states like flow or emotional relief. Logistics during the ultramarathon also meant that pre-race samples for the 230-kilometer group had to be collected the previous evening rather than right at the starting line.
“One important distinction is that we measured endocannabinoids in the blood, not directly in the brain,” Siebers pointed out. “Although our findings show substantial changes in circulating endocannabinoid concentrations, we cannot yet determine precisely what happens in the brain during prolonged running.”
“Another important point is that the runner’s high is not simply caused by one molecule,” he added. “Endocannabinoids are probably part of a much larger and highly complex orchestra of neuromodulators, including dopamine, serotonin, endogenous opioids, and other signaling systems. Furthermore, not everyone experiences a runner’s high, and running does not necessarily become more enjoyable the longer someone continues.”
When considering future research, McCartney highlighted both pharmacological and nutritional avenues for follow-up testing. “Ideally, I’d like to see whether blocking cannabinoid receptors prevents the runner’s high,” she said. “Unfortunately, the safety concerns associated with drugs like rimonabant make that a difficult experiment to conduct in humans!”
Rimonabant, a drug that blocks the main cannabinoid receptor, was pulled from the European market in 2008 after it was linked to depression and suicidal thoughts.
“More realistically, I’d be interested in seeing whether nutrition influences the endocannabinoid response to prolonged exercise,” McCartney told PsyPost, “particularly given that runners typically consume substantial amounts of carbohydrate during marathon and ultramarathon events.”
Looking ahead, the authors hope to examine how these chemical messengers operate directly within the central nervous system during physical exertion.
“One of my main interests is understanding how running influences mood changes and the brain itself,” Siebers said. “So far, our research has primarily focused on measuring endocannabinoids in peripheral blood. However, the runner’s high ultimately involves processes within the central nervous system, and we still know surprisingly little about what actually happens in the human brain during running. I would therefore like to investigate these central mechanisms more directly, potentially through neuroimaging and other methods that allow us to study neuromodulation in the brain.”
“In addition, I am particularly interested in how the endocannabinoid system interacts with pain regulation during prolonged exercise,” he continued. “Why can some individuals continue running for hours despite considerable physical stress, while others experience increasing discomfort? Understanding these mechanisms could provide valuable insights not only into endurance exercise but also into pain regulation and mental health.”
Beyond laboratory measurements, the researchers also reflected on the broader personal and evolutionary dimensions of sustained running.
Siebers emphasized that the effect requires no outside substance. “What fascinates me is that our bodies can produce their own cannabis-like substances simply through physical activity,” he told PsyPost. “Under the right circumstances, this can contribute to a completely natural high, without consuming any external substance.”
“For me, the most exciting message is that running is much more than moving our legs,” Siebers said. “It is a fascinating interaction between our body and brain, and understanding this interaction may help us discover why humans have developed such an extraordinary relationship with endurance running.”
The study, “Endocannabinoid dynamics across marathon and ultramarathon running: evidence from two field studies,” was authored by Michael Siebers, Dana Huvermann, Christoph Siebers, Deborah Canales-Romero, Alexandra Florea-Ghile, Lina Keite, Lucas John, Moritz Munk, Roman Bizjak, Jens Witzel, Sebastian Schulz, Johannes Kirsten, Laura Bindila, Anke Hinney, Marijke Grau, Daniel A. Bizjak, Harald Engler, and Johannes Fuss.
-------------------------------------------------
Private, vetted email list for mental health professionals: https://www.clinicians-exchange.org
Unofficial Psychology Today Xitter to toot feed at Psych Today Unofficial Bot @PTUnofficialBot
-------------------------------------------------
#psychology #counseling #socialwork #psychotherapy @psychotherapist @psychotherapists @psychology @socialpsych @socialwork @psychiatry #mentalhealth #psychiatry #healthcare #depression #psychotherapist #RunnersHigh #Running #Marathon #Ultramarathon #EnduranceRunning #SportsScience #Neuroscience #Endocannabinoids #Anandamide #MentalWellness
-
Nos artigos anteriores construímos uma visão cada vez mais completa do Apache Spark.
Passamos por:
Data
↓
Partitions
↓
Tasks
↓
Executors
↓
Shuffle
↓
Joins
↓
Spark SQL
↓
Catalyst
↓
Physical PlanMas existe um recurso atravessando praticamente todas essas etapas:
memória.
Quando comecei a estudar problemas de memória no Spark, era tentador resumir tudo a:
OutOfMemory
↓
aumentar RAMHoje eu vejo esse raciocínio como incompleto.
Um problema de memória pode estar relacionado a:
Driver
Executors
Partitions
Shuffle
Broadcast
Cache
Serialization
Garbage Collection
Python workers
Off-heap/native memory
Memory OverheadE aumentar memória sem descobrir qual desses componentes está causando o problema pode apenas tornar um Job caro antes de ele falhar novamente.
A pergunta correta não é:
Quanto de memória devo adicionar?
É:Quem está consumindo memória, por quê, e em qual parte da arquitetura?
1. Memória em uma aplicação Spark
Vamos voltar à arquitetura básica:DRIVER
│
▼
Cluster Manager
│
┌─────────┼─────────┐
▼ ▼ ▼
Executor 1 Executor 2 Executor 3Temos dois contextos que precisam ser diferenciados imediatamente:
Driver Memory
e:
Executor Memory
Essa distinção é fundamental.
Porque:
Driver OOM
e:
Executor OOM
podem ter causas completamente diferentes.
2. Driver Memory
O Driver coordena a aplicação.Ele mantém informações relacionadas a:
- aplicação;
- Jobs;
- Stages;
- Tasks;
- scheduling;
- metadados;
- planos de execução;
- resultados retornados ao Driver;
- estado necessário para coordenar a computação.
Conceitualmente:
DRIVER
│
┌──────────────┼──────────────┐
▼ ▼ ▼
Planning Scheduling Metadata
│ │ │
└──────────────┼──────────────┘
▼
ControlIsso significa que o Driver não deveria ser tratado como destino para todo o dataset distribuído.
Esse ponto parece óbvio.
Até alguém executar:
dados = df.collect()
3. O perigo do
collect()
Considere:df.count()
O processamento acontece de maneira distribuída e o resultado retornado é pequeno:
123456789
Agora compare com:
dados = df.collect()
collect()solicita que todos os registros do DataFrame sejam retornados ao Driver.Conceitualmente:
Executor 1 ──────┐
Executor 2 ──────┤
Executor 3 ──────┼──► DRIVER
Executor 4 ──────┤
Executor 5 ──────┘Se o dataset possuir:
500 GB
e o Driver tiver:
8 GB
temos um problema bastante previsível.
O Spark é distribuído.
Mas acabamos de pedir:
Traga tudo para uma única máquina.
4.
collect()não é ruim — o contexto é que importa
Não existe problema em:df.limit(10).collect()
quando sabemos que o resultado será pequeno.
Também existem cenários legítimos em que precisamos trazer pequenas quantidades de dados ao Driver.
O problema é usar
collect()sem compreender:Distributed Dataset
↓
DriverA pergunta antes de um
collect()deveria ser:Qual o volume máximo que pode voltar para o Driver?
Essa pergunta evita muitos problemas.
5. Outros caminhos para sobrecarregar o Driver
collect()é o exemplo mais conhecido, mas não é o único.Problemas de Driver também podem aparecer com:
- resultados excessivamente grandes;
- estruturas locais gigantes;
- excesso de metadados;
- quantidade extrema de Tasks;
- operações que materializam dados no processo do Driver;
- código Python executado localmente;
- determinadas operações de visualização ou conversão.
Por exemplo:
pdf = df.toPandas()
merece atenção.
O resultado precisa caber na memória do processo que recebe esse DataFrame local.
Ou seja:
Spark DataFrame distribuído
↓
toPandas()
↓
DataFrame local
↓
DRIVERSe os dados forem grandes, temos novamente uma concentração de memória.
6. Executor Memory
Agora vamos para os Executors.Eles executam as Tasks.
Conceitualmente:
Executor
│
├── Task 1
├── Task 2
├── Task 3
└── Task 4Durante a execução, memória pode ser necessária para:
- processamento;
- agregações;
- joins;
- sorting;
- shuffle;
- estruturas intermediárias;
- cache;
- dados serializados;
- execução de código;
- componentes fora do heap JVM.
É aqui que começam vários problemas clássicos.
7. Uma partição vira trabalho para uma Task
Da Parte 3:Em uma determinada Stage, cada partição normalmente corresponde ao trabalho de uma Task.
Então existe uma conexão direta:Partition
↓
Task
↓
Memory pressureImagine:
Partition 1 → 200 MB
Partition 2 → 180 MB
Partition 3 → 220 MB
Partition 4 → 18 GBA Task responsável pela quarta partição terá um perfil completamente diferente das demais.
Podemos observar:
Task 1 → OK
Task 2 → OK
Task 3 → OK
Task 4 → Memory PressureTalvez o problema não seja:
Executor com pouca memória.
Talvez seja:Uma partição absurdamente maior que as outras.
8. Particionamento e memória são inseparáveis
Imagine um dataset de:1 TB
distribuído em:
10 partitions
Simplificando muito:
≈ 100 GB por partition
Agora considere:
1000 partitions
Teríamos algo mais próximo de:
≈ 1 GB por partition
Isso não significa que uma Task precise manter toda a partição simultaneamente em memória.
Mas o exemplo mostra uma relação importante:
O tamanho e a distribuição das partições influenciam diretamente a pressão de memória das Tasks.
É por isso que simplesmente aumentarspark.executor.memorypode esconder a causa real.
9. Execution Memory
Durante operações como:df.groupBy("customer_id").sum("value")
Spark precisa de memória para executar estruturas intermediárias.
Também em:
df.orderBy("timestamp")
ou em determinados joins.
Podemos pensar conceitualmente:
Executor Memory
│
├── Execution
│ │
│ ├── Shuffle
│ ├── Join
│ ├── Sort
│ └── Aggregation
│
└── Storage
│
├── Cached Data
└── Persisted DataNo Spark moderno, execution e storage participam de um modelo de gerenciamento de memória integrado.
Isso é importante porque a memória disponível não deve ser imaginada como caixas totalmente independentes e rígidas em todos os momentos.
10. Storage Memory
Agora imagine:df.cache()
Quando o DataFrame é materializado, Spark pode manter partições para reutilização.
Conceitualmente:
Executor
│
├── Execution Memory
│
└── Storage Memory
│
├── Partition A
├── Partition B
└── Partition CIsso pode ser extremamente útil.
Se o mesmo dataset caro for utilizado várias vezes:
Expensive computation
↓
CACHE
↓
┌─────┼─────┐
▼ ▼ ▼
Use 1 Use 2 Use 3evitamos recalcular repetidamente a mesma linhagem.
Mas cache também custa memória.
11.
cache()não significa "deixe rápido"
Esse é outro anti-pattern comum:df.cache()
ser utilizado como se significasse:
optimize(df)
Não significa.
Imagine um DataFrame de:
800 GB
que será utilizado apenas uma vez.
Fazer cache pode simplesmente:
- consumir memória;
- provocar eviction;
- aumentar pressão sobre o Executor;
- competir com execution memory;
- não trazer benefício relevante.
Cache faz mais sentido quando existe reuso.
Por exemplo:
base = transformacao_cara(df)
base.cache()
resultado_a = base.groupBy("estado").count()
resultado_b = base.groupBy("produto").sum("valor")
resultado_c = base.filter("status = 'ACTIVE'")Agora existe um motivo claro:
Expensive Base
↓
CACHE
↓
┌────┼────┐
▼ ▼ ▼
A B C12. Cache também é Lazy
Considere:df.cache()
Isso não significa necessariamente:
Neste instante, todas as partições foram computadas e armazenadas.
A materialização ocorre quando uma Action força a computação.Por exemplo:
df.cache()
df.count()
Agora temos:
cache()
↓
mark for persistence
↓
count()
↓
compute partitions
↓
store according to persistence strategyLazy evaluation continua presente.
13.
persist()
Além de:df.cache()
podemos trabalhar com:
df.persist()
e escolher estratégias de persistência adequadas ao contexto.
Conceitualmente, a persistência pode envolver combinações de:
Memory
Disk
Serialization
ReplicationA escolha depende de fatores como:
- tamanho;
- frequência de reuso;
- custo de recomputação;
- memória disponível;
- tolerância a I/O.
Novamente, não existe uma configuração universalmente melhor.
14. E quando a memória não é suficiente?
Agora chegamos a algo que apareceu na Parte 4:Spill
Imagine uma Task realizando:Sort
ou:
Aggregation
ou processamento relacionado a:
Shuffle
Ela utiliza estruturas em memória.
Mas a quantidade necessária ultrapassa o que pode ser mantido eficientemente ali.
Então parte dos dados pode ser enviada para disco.
Conceitualmente:
Task
↓
Memory
↓
Memory pressure
↓
Spill
↓
DiskDepois:
Disk
↓
Read
↓
Continue processingIsso permite que determinadas operações continuem mesmo quando tudo não cabe simultaneamente em memória.
Mas existe um preço.
15. Spill troca memória por I/O
Compare:Memory
↓
CPUcom:
Memory
↓
Disk Write
↓
Disk Read
↓
CPUDisco normalmente é muito mais lento do que memória.
Então grandes volumes de spill podem transformar:
Job
em:
Job lento
Mesmo sem ocorrer um OutOfMemory.
Essa é uma lição importante:
Uma aplicação pode estar sofrendo de pressão de memória sem necessariamente falhar por OOM.
Ela pode simplesmente ficar muito mais lenta.
16. Shuffle + Memory + Spill
Agora conectamos vários artigos.Considere:
resultado = (
vendas
.groupBy("customer_id")
.sum("valor")
)Podemos ter:
Partitions
↓
Partial Aggregation
↓
Shuffle Write
↓
Network
↓
Shuffle Read
↓
Aggregation
↓
Memory pressure
↓
Spill
↓
DiskAgora um simples:
groupBy()
ganha uma interpretação completamente diferente.
17. Data Skew volta novamente
Imagine:P1 = 200 MB
P2 = 210 MB
P3 = 190 MB
P4 = 15 GBDurante uma agregação:
P1 → OK
P2 → OK
P3 → OK
P4 → Spill → Spill → SpillOu pior:
P4 → OutOfMemory
A reação inicial pode ser:
Aumentar executor memory.
Talvez funcione.Mas talvez a pergunta correta seja:
Por que existe uma partição de 15 GB quando as demais possuem aproximadamente 200 MB?
Estamos novamente diante de:Data Skew
A causa é distribuição.
O sintoma aparece na memória.
18. OutOfMemory não é um único problema
Quando alguém diz:"Spark deu OOM."
Ainda sabemos muito pouco.Precisamos perguntar:
Onde?
Por exemplo:
Driver OOM?
ou:
Executor OOM?
ou pressão fora do heap/container?
Também precisamos perguntar:
Em qual Stage?
Em qual operação?
Em todas as Tasks?
Em uma única Task?
Depois de um Shuffle?
Durante Broadcast?
Durante collect()?
Essas perguntas mudam completamente a investigação.
19. Um Driver OOM pode indicar problema de arquitetura
Imagine:dados = df.collect()
sobre um dataset enorme.
Podemos aumentar:
spark.driver.memory
de:
4 GB
para:
16 GB
Depois:
32 GB
Depois:
64 GB
Talvez o Job finalmente funcione.
Mas a pergunta continua:
Por que estamos trazendo um dataset distribuído gigantesco para um único processo?
Aumentar memória resolveu o sintoma.Talvez não tenha resolvido o design.
20. Executor OOM também pode esconder outro problema
Agora imagine:Executor OOM
A reação:
spark.executor.memory
8 GB → 16 GBMas talvez exista:
uma partition = 40 GB
Ou:
join skewed
Ou:
broadcast excessivo
Ou várias Tasks concorrentes disputando recursos.
Ou consumo significativo fora do heap principal.
Então:
Executor OOM não significa automaticamente que o Executor precisa apenas de mais heap.
21.
spark.executor.memory
Uma configuração conhecida é:spark.executor.memory
Ela define a quantidade de memória heap disponibilizada ao processo Executor JVM.
Por exemplo:
--executor-memory 8g
Mas existe uma armadilha conceitual importante:
A memória total necessária por um Executor não é necessariamente igual ao valor de
spark.executor.memory.
Existe memória utilizada fora desse heap.E isso nos leva diretamente ao tema do material original que estudei:
Memory Overhead
22. O que é Memory Overhead?
Uma aplicação Spark não utiliza memória apenas para o heap principal da JVM.Podemos pensar de forma simplificada:
Executor Container / Process Environment
│
├── JVM Heap
│
│ └── spark.executor.memory
│
└── Additional / Non-Heap Memory
│
├── JVM overhead
├── native memory
├── Python processes
├── direct buffers
└── other runtime overheadÉ essa segunda região que torna
memoryOverheadtão importante.Dependendo do ambiente e do workload, um Executor pode morrer mesmo quando aparentemente existe heap suficiente.
23. Um exemplo conceitual
Imagine uma configuração:Executor Heap
8 GBIsso não significa necessariamente:
Executor total
=
8 GBO processo também precisa de espaço para outras necessidades.
Podemos pensar:
Container / Pod / Executor allocation
┌───────────────────────────────┐
│ │
│ JVM Heap │
│ spark.executor.memory │
│ │
├───────────────────────────────┤
│ │
│ Memory Overhead │
│ │
│ Native / Python / Direct / │
│ JVM non-heap / other │
│ │
└───────────────────────────────┘Se a região adicional for insuficiente, o processo pode exceder os limites impostos pelo gerenciador de recursos.
24. Por que isso aparece muito com PySpark?
Em PySpark existe uma característica importante.Nosso código Python não transforma a JVM inteira em Python.
Existe interação entre:
JVM
↕
Python workerConceitualmente:
Executor JVM
│
├── Spark execution
│
└── Python worker
│
└── Python codeEsses processos também consomem memória.
Dependendo do workload, bibliotecas e operações utilizadas, isso pode se tornar relevante para o consumo total do Executor.
Portanto, em PySpark precisamos olhar além de:
JVM Heap
25. Memory Overhead no material histórico
Uma das anotações que motivou este capítulo tratava especificamente de problemas dememoryOverhead.Esse tipo de problema continua conceitualmente relevante.
O que mudou ao longo dos anos foram:
- versões do Spark;
- nomes e comportamento de determinadas configurações;
- resource managers;
- defaults;
- cálculo automático de overhead;
- integração com containers;
- Kubernetes;
- execução Python;
- mecanismos internos de memória.
Por isso não considero uma boa prática pegar uma configuração antiga e simplesmente reproduzi-la hoje.
O conceito continua válido.
A configuração precisa ser analisada no contexto da versão e do ambiente atuais.
26. Heap vs. Off-Heap vs. Overhead
Uma simplificação útil é:PROCESS MEMORY
│
├── JVM Heap
│
├── JVM Non-Heap
│
├── Direct / Native Memory
│
├── Python Worker Memory
│
└── Runtime OverheadIsso é mais próximo da realidade do que pensar:
memory = spark.executor.memory
Quando um container é encerrado por ultrapassar limite de memória, precisamos descobrir qual parte do consumo cresceu.
27. Garbage Collection
Agora vamos entrar em outro sintoma importante:GC
A JVM gerencia automaticamente memória de objetos.Objetos são criados:
Objects
↓
HeapDepois deixam de ser necessários.
O Garbage Collector precisa recuperar esse espaço.
Em um cenário saudável:
Application Work ███████████████████
GC █
Mas sob forte pressão podemos encontrar algo mais próximo de:
Application ███████
GC █████████████
Ou seja:
A aplicação passa tempo demais tentando gerenciar memória em vez de processar dados.
28. GC alto é sintoma
Assim como OOM, GC excessivo não deveria gerar automaticamente:Aumente a heap.
Talvez tenhamos:- objetos demais;
- partições grandes;
- agregações pesadas;
- estruturas intermediárias enormes;
- cache excessivo;
- serialização inadequada;
- concorrência excessiva por Executor.
Precisamos descobrir por que a memória está sob pressão.
29. Mais cores por Executor também afetam memória
Imagine:Executor
8 coresDependendo da configuração, várias Tasks podem executar simultaneamente nesse Executor.
Conceitualmente:
Executor Memory
│
┌────┼────┬────┬────┬────┐
▼ ▼ ▼ ▼ ▼ ▼
T1 T2 T3 T4 T5 ...Cada Task pode precisar de memória.
Então existe uma relação:
mais Tasks concorrentes por Executor
↓
mais competição pela memória disponívelIsso mostra por que tuning não deveria analisar:
executor memory
isoladamente.
Precisamos olhar para:
Executor Memory
+
Executor Cores
+
Partition Size
+
Task Behavior30. Executors gigantes também não são automaticamente melhores
Poderíamos pensar:1 Executor
64 cores
256 GB RAMParece poderoso.
Mas Executors gigantes podem trazer trade-offs relacionados a:
- concorrência;
- garbage collection;
- blast radius de falha;
- utilização;
- scheduling;
- memória compartilhada entre muitas Tasks.
No outro extremo:
64 Executors
1 core
4 GBtambém possui trade-offs.
Não existe um tamanho universal.
Precisamos equilibrar:
cores
memory
parallelism
partition size
workload
cluster manager31. Broadcast também consome memória
Na Parte 5 vimos:from pyspark.sql.functions import broadcast
resultado = grande.join(
broadcast(pequena),
"id"
)A estratégia pode evitar um shuffle grande.
Mas existe um custo:
Small Table
↓
Broadcast
┌──┼──┐
▼ ▼ ▼
E1 E2 E3Cada Executor precisa conseguir trabalhar com a estrutura transmitida.
Se tentarmos broadcast de algo grande demais, podemos criar pressão significativa de memória.
Novamente:
Network optimization
↕
Memory costSistemas distribuídos são cheios de trade-offs.
32. Cache também compete por recursos
Imagine:df_a.cache()
df_b.cache()
df_c.cache()
df_d.cache()Pode parecer:
Quanto mais cache, melhor.
Mas:Cache A
Cache B
Cache C
Cache D
↓
Storage Pressure
↓
Eviction / recomputation / resource competitionCache deveria ser uma decisão baseada em:
reuse frequency
×
recomputation cost
×
available resourcese não um reflexo automático.
33.
unpersist()
Se um dataset não será mais reutilizado, podemos liberar sua persistência:df.unpersist()
Isso comunica:
Não preciso mais manter essas partições persistidas.
Em pipelines longos isso pode ser importante.Por exemplo:
Phase A
↓
cache intermediate
↓
reuse several times
↓
phase completed
↓
unpersist
↓
free resources for Phase BGerenciamento de memória também faz parte do design do pipeline.
34. O Spark UI volta a ser essencial
Se existe problema de memória, não quero começar alterando configurações.Quero observar.
No Spark UI e métricas relacionadas, procuro sinais como:
Task Duration
GC Time
Shuffle Read
Shuffle Write
Spill
Storage
Executor behavior
Failed Tasks
SkewTambém observo logs.
A pergunta é:
O que aconteceu antes da falha?
35. Um padrão de investigação
Imagine:Job falhou
↓
Executor lost
↓
Memory-related errorMeu raciocínio começaria assim:
Qual Stage?
↓
Qual operação?
↓
Join?
Aggregation?
Sort?
UDF?
Cache?Depois:
Todas as Tasks falharam?
↓
ou apenas algumas?Se apenas algumas:
Possível skew?
Depois:
Qual tamanho das partitions?
Quanto shuffle?
Quanto spill?
Quanto GC?Só então:
Heap insuficiente?
Overhead insuficiente?
Particionamento ruim?
Broadcast inadequado?
Concorrência excessiva?36. Caso 1 — Driver morrendo
Sintoma:Driver OutOfMemory
Código:
dados = df.collect()
Dataset:
120 GB
Driver:
8 GB
Diagnóstico provável:
Distributed Data
↓
collect()
↓
Single Process
↓
OOMSolução arquitetural:
Não coletar o dataset inteiro.
Talvez:df.write.parquet(
"/data/output"
)ou continuar o processamento distribuído.
A solução principal não é necessariamente:
8 GB → 128 GB
37. Caso 2 — Uma Task morre repetidamente
Sintoma:Stage 12
199 Tasks → OK
1 Task → FAILIsso é extremamente informativo.
Talvez tenhamos:
Data Skew
ou uma partição muito maior.
Se aumentarmos memória de todos os Executors:
Cluster cost ↑
para resolver uma única partição anormal, talvez estejamos atacando o lugar errado.
Precisamos investigar a distribuição.
38. Caso 3 — Todas as Tasks sofrem Spill
Imagine:Task 1 → heavy spill
Task 2 → heavy spill
Task 3 → heavy spill
Task 4 → heavy spill
...Agora talvez tenhamos um problema sistêmico.
Possíveis causas:
Partitions muito grandes
Memory insuficiente
Join pesado
Sort pesado
Aggregation pesada
Task concurrencyNesse cenário, ajustar recursos pode realmente fazer parte da solução.
Mas ainda precisamos medir.
39. Caso 4 — OOM depois de Broadcast
Imagine que:Job funcionava
e alguém adicionou:
broadcast(dim)
Agora Executors começam a morrer.
Pergunta:
Qual o tamanho real de dim?
Talvez:
"small table"
tenha crescido.
Ontem:
50 MB
Hoje:
6 GB
Uma otimização válida no passado pode se tornar um problema quando os dados mudam.
Isso é importante:
Performance depende também da evolução dos dados.
40. Caso 5 — PySpark e memória externa ao heap
Imagine:spark.executor.memory
aparentemente confortável.
Mas containers continuam sendo encerrados por memória.
Agora precisamos olhar para:
JVM Heap
+
Python workers
+
Native memory
+
Direct buffers
+
Other overheadÉ exatamente nesse tipo de cenário que compreender
memoryOverheaddeixa de ser detalhe e passa a ser parte do diagnóstico.
41. Não ajuste
memoryOverheadàs cegas
Se um Executor morre por ultrapassar limites externos ao heap, aumentar overhead pode ser apropriado.Mas ainda precisamos perguntar:
Por que esse consumo existe?
Pode ser:
- Python;
- bibliotecas nativas;
- buffers;
- comportamento da JVM;
- volume de dados;
- operação específica.
A configuração correta depende do workload e do ambiente.
Por isso evito recomendações como:
sempre configure X GB
ou:
sempre use Y%
sem contexto.
Defaults e comportamentos também evoluem entre versões.
42. Memória em Kubernetes
Em ambientes containerizados, a questão fica ainda mais visível.Podemos pensar:
Kubernetes Pod
│
└── Executor
│
├── JVM Heap
├── Non-Heap
├── Native
├── Python
└── OverheadO Pod possui limites.
Não basta a JVM achar que possui heap suficiente.
O consumo total do processo e componentes associados precisa respeitar os recursos disponíveis.
Esse é um dos motivos pelos quais problemas modernos de Spark precisam ser analisados também no nível da infraestrutura.
43. Memória em YARN
Em ambientes YARN, existe raciocínio semelhante.O Executor executa dentro de recursos controlados pelo gerenciador do cluster.
Historicamente, muitos erros de
memoryOverheadficaram conhecidos justamente em ambientes onde o container ultrapassava seu limite mesmo quando a heap configurada parecia aceitável.O princípio permanece:
JVM Heap
≠
Total Process Memory44. A configuração depende do ambiente
Hoje Spark pode rodar em diferentes contextos:Standalone
YARN
Kubernetes
Managed Platforms
Cloud ServicesIsso significa que recomendações de memória precisam considerar:
- Spark version;
- cluster manager;
- container limits;
- JVM;
- Python;
- workload;
- plataforma gerenciada.
Uma configuração copiada de um artigo antigo pode estar:
correta historicamente
e:
inadequada atualmente
ao mesmo tempo.
Esse é exatamente o tipo de cuidado que estou aplicando ao revisitar meu material antigo nesta série.
45. Um modelo mental melhor para OOM
Em vez de:OOM
↓
More Memoryprefiro:
OOM
│
┌──────────┴──────────┐
▼ ▼
Driver? Executor?
│ │
▼ ▼
collect()? Which Stage?
toPandas()? │
metadata? ▼
Which Operation?
│
┌──────────┼──────────┐
▼ ▼ ▼
Skew Shuffle Broadcast
│ │ │
└──────────┼──────────┘
▼
Partition Size
│
▼
Heap or Overhead?
│
▼
Root CauseEsse modelo evita tratar todos os erros de memória como iguais.
46. Performance tuning começa com observabilidade
Imagine dois engenheiros.O primeiro vê:
OutOfMemoryError
e imediatamente altera:
spark.executor.memory
O segundo investiga:
Stage
Tasks
Partition distribution
Shuffle
Spill
GC
Executor logs
Physical plan
Data volumeO segundo talvez leve alguns minutos a mais antes de alterar a configuração.
Mas a chance de resolver a causa real é muito maior.
Essa é uma diferença importante entre:
configuration tuning
e:
performance engineering
47. Um checklist para problemas de memória
Quando encontro um problema de memória em Spark, quero responder:- O erro aconteceu no Driver ou Executor?
- Qual Stage estava executando?
- Qual operação estava acontecendo?
- Existe
collect()? - Existe
toPandas()? - Existe broadcast?
- Existe cache excessivo?
- As partições estão equilibradas?
- Existe data skew?
- Qual o tamanho das maiores Tasks?
- Existe Shuffle?
- Quanto?
- Existe Spill?
- Quanto?
- Quanto tempo está sendo gasto em GC?
- Todas as Tasks sofrem ou apenas algumas?
- Existem Python workers?
- Existe consumo nativo relevante?
- O limite do container está sendo ultrapassado?
- O problema é heap ou overhead?
- A configuração corresponde à versão e ao cluster manager utilizados?
Só depois:
Qual configuração preciso alterar?
48. O que eu evitaria fazer automaticamente
Se o Job estiver lento ou falhando, eu evitaria começar por:dobrar executor memory
ou:
dobrar driver memory
ou:
aumentar memoryOverhead arbitrariamente
ou:
cachear tudo
ou:
reduzir o número de partitions sem medir
ou:
aumentar o cluster
Todas essas ações podem ser válidas.
Mas nenhuma delas deveria substituir diagnóstico.
49. Memória, performance e custo
Em cloud, existe ainda outra dimensão.Imagine:
Executor Memory
8 GBe simplesmente dobramos para:
16 GB
em dezenas ou centenas de Executors.
Talvez o Job fique estável.
Mas talvez tenhamos acabado de aumentar recursos para compensar:
Data Skew
ou:
repartition ruim
ou:
join inadequado
ou:
cache desnecessário
Então temos:
Problema arquitetural
↓
Mais infraestrutura
↓
Maior custo
↓
Problema mascaradoPerformance tuning também é FinOps.
50. A conexão entre tudo que vimos até aqui
Agora podemos montar uma visão muito mais completa:DATA
│
▼
PARTITIONS
│
▼
TASKS
│
▼
EXECUTORS
│
┌───────────┼───────────┐
▼ ▼ ▼
Memory CPU Network
│ │
▼ ▼
Aggregation Shuffle
│ │
└───────────┬───────────┘
▼
Spill
│
▼
Disk
│
▼
Performance
│
▼
CostAgora adicione:
Data Skew
e podemos gerar:
Uneven Partition
↓
Huge Task
↓
Memory Pressure
↓
Spill / GC
↓
Slow Task
↓
Straggler
↓
Slow StageIsso mostra por que os capítulos anteriores estavam conectados.
51. A principal lição deste capítulo
Se eu pudesse resumir memória no Spark em uma frase:Problemas de memória frequentemente são sintomas de como os dados e a computação foram distribuídos.
Nem sempre.Às vezes realmente precisamos de mais memória.
Mas antes de aumentar recursos, quero saber:
Quem está consumindo?
↓
Onde?
↓
Durante qual operação?
↓
Por quê?Só então:
Architecture
+
Configuration
+
Resourcesentram na solução.
52. Como penso hoje
Meu modelo mental deixou de ser:Spark OOM
↓
Increase Memorye passou a ser:
Spark OOM
↓
Driver or Executor?
↓
Heap or Overhead?
↓
Which Stage?
↓
Which Task?
↓
Which Operation?
↓
Partition Size?
↓
Skew?
↓
Shuffle?
↓
Spill?
↓
Broadcast?
↓
Cache?
↓
Python / Native Memory?
↓
Root Cause
↓
Then TuneEsse raciocínio é muito mais útil do que decorar valores de configuração.
Próximo artigo
Agora entendemos:Partitions
↓
Tasks
↓
Memory
↓
Shuffle
↓
SpillMas existe outro conceito fundamental que apareceu desde os primeiros artigos:
Lineage.
Quando uma partição é perdida, como Spark sabe reconstruí-la?
Por que RDD significa:
Resilient Distributed Dataset
?
Como Spark obtém tolerância a falhas sem simplesmente replicar toda computação intermediária?
E o que acontece quando a linhagem fica grande demais?
No próximo artigo vamos explorar:
- RDD Lineage;
- DAG;
- fault tolerance;
- recomputation;
- cache vs. recomputation;
- checkpoint;
- persistência;
- falha de Executor;
- recuperação de partições;
- por que Spark é "resilient";
- e como essas ideias evoluíram nas APIs modernas.
Vamos partir deste modelo:
Source
↓
Map
↓
Filter
↓
Join
↓
Aggregate
↓
Resultpara enxergar algo mais profundo:
LINEAGE
│
▼
Source → Transform → Transform → Shuffle → Result
│ │ │
└──────────┴──────────┘
│
information needed
for recomputationEssa é uma das ideias fundamentais que fizeram o Spark ser Spark.
← Parte 6: Spark SQL e DataFrames — do código ao plano de execução
Próximo: Parte 8 — RDD Lineage e tolerância a falhas: como o Spark se recupera quando algo dá errado#cluster #spark #python #bigdata #software #coding #development #engineering #inclusive #community
Como aprendi Apache Spark — Parte 7: Memória — Executors, Driver, Cache, Spill e OutOfMemory -
Reklam panelinde "lead" sayısı artarken satış ekibinin "bu lead'lerin hiçbiri alıcı değil" demesi, dijital pazarlamada en sık duyduğum cümlelerden biri. Ben Koray Yalçın; lead yönetimi, CRM mimarisi, dijital pazarlama ve yapay zekâ destekli otomasyonların kesiştiği projelerde çalışıyorum, özellikle gayrimenkul ve B2B tarafında. Bu cümlenin arkasında çoğu zaman teknik bir kopukluk yatar: Reklam platformu formun doldurulduğunu bilir, ama o kişinin üç hafta sonra showroom'a gelip sözleşme imzaladığını bilmez. Algoritma da doğal olarak form doldurmaya en yatkın kitleyi bulmaya devam eder, satın almaya en yatkın kitleyi değil.
Bu boşluğu kapatmanın yolu, CRM'de oluşan "nitelikli lead", "randevu gerçekleşti" ve "satış kapandı" gibi olayları sunucu tarafından Meta Conversions API'ye (CAPI) geri göndermek. Bu yazı bir pazarlama rehberi değil; bu köprüyü kodla kurarken karşılaştığım tasarım kararlarını anlatıyor: kullanıcı verisinin normalizasyonu ve hash'lenmesi, olay kimliği ile tekilleştirme, zaman penceresi, yeniden deneme stratejisi ve izin kontrolü. Örnekler Python ama mantık her dile taşınabilir.
Önce olay sözlüğü: Hangi CRM durumu hangi olay?
CRM olayıGönderilen olay adıNotForm / lead oluştu
Kod yazmadan önce yapılması gereken en önemli iş, CRM'deki aşamaları sınırlı ve anlamlı bir olay listesine eşlemek. Her aşama değişikliğini Meta'ya göndermek gürültü üretir. Benim kullandığım tipik eşleme şöyle:LeadGenellikle tarayıcı pikseli zaten gönderirTemsilci "nitelikli" işaretlediQualifiedLead(özel olay)Ölçüm kurgusuna göre seçilirRandevu gerçekleştiScheduleveya özel olay"Randevu alındı" değil, "gerçekleşti"Sözleşme imzalandıPurchasevaluevecurrencyzorunlu düşünülmeli
Burada kritik nokta şu: Olay, CRM'de geri alınabilir bir alan değişikliğinden değil, kalıcı bir olaydan tetiklenmeli. Temsilci bir fırsatı yanlışlıkla "kazanıldı" yapıp beş dakika sonra geri alırsa, gönderilmiş birPurchaseolayını geri çekmenin pratik bir yolu yoktur. Bu yüzden ben aşama değişikliklerini doğrudan API'ye bağlamak yerine birconversion_eventstablosuna yazıyorum ve gönderimi kısa bir bekleme süresinden sonra yapan ayrı bir işçiye bırakıyorum.CREATE TABLE conversion_events (
id BIGSERIAL PRIMARY KEY,
event_id TEXT NOT NULL UNIQUE, -- tekilleştirme anahtarı
event_name TEXT NOT NULL,
lead_id BIGINT NOT NULL REFERENCES leads(id),
occurred_at TIMESTAMPTZ NOT NULL, -- olayın gerçek zamanı
value_minor BIGINT, -- kuruş/cent cinsinden
currency CHAR(3),
status TEXT NOT NULL DEFAULT 'pending', -- pending, sent, failed, skipped
attempts INT NOT NULL DEFAULT 0,
last_error TEXT,
send_after TIMESTAMPTZ NOT NULL DEFAULT now() + interval '15 minutes'
);send_afteralanı, "yanlışlıkla kazanıldı" senaryosuna karşı küçük bir tampon. İşçi göndermeden önce fırsatın hâlâ aynı aşamada olup olmadığını kontrol eder; değilse kaydıskippedyapar.Kullanıcı verisini normalize etmek: Hash'ten önce gelen asıl iş
CAPI, e-posta ve telefon gibi kişisel verilerin SHA-256 ile hash'lenmiş olarak gönderilmesini bekler. Çoğu ekiphashlib.sha256(email)yazıp işi bitmiş sayar. Sorun şu ki hash, girdideki tek bir boşluğu ya da büyük harfi tamamen farklı bir değere dönüştürür. Meta tarafındaki eşleşme de birebir karşılaştırmayla çalıştığı için normalizasyon hatası, sessizce düşük eşleşme oranı olarak geri döner.Benim sahada gördüğüm en yaygın hatalar:
- E-postada baştaki/sondaki boşluklar ve büyük harfler.
- Telefonun
0533 ...,+90 533 ...,90533...gibi farklı biçimlerde saklanması. - İsimlerde Türkçe karakterlerin farklı yazımları ve "Dr." gibi önekler.
- Boş alanların boş string olarak hash'lenmesi (boş string'in de bir SHA-256 değeri vardır ve anlamsız bir eşleşme anahtarı üretir).
import hashlib
import re
import phonenumbersdef _sha256(value: str) -> str:
return hashlib.sha256(value.encode("utf-8")).hexdigest()def norm_email(raw: str | None) -> str | None:
if not raw:
return None
v = raw.strip().lower()
return v if "@" in v else Nonedef norm_phone(raw: str | None, default_region: str = "TR") -> str | None:
if not raw:
return None
try:
num = phonenumbers.parse(raw, default_region)
except phonenumbers.NumberParseException:
return None
if not phonenumbers.is_valid_number(num):
return None
# Ülke kodu dahil, yalnızca rakamlar, başta + yok
return phonenumbers.format_number(num, phonenumbers.PhoneNumberFormat.E164).lstrip("+")def build_user_data(lead) -> dict:
ud = {}
if (e := norm_email(lead.email)):
ud["em"] = [_sha256(e)]
if (p := norm_phone(lead.phone, lead.country_code or "TR")):
ud["ph"] = [_sha256(p)]
if lead.external_id:
ud["external_id"] = [_sha256(str(lead.external_id))]
# Tarayıcıdan yakalandıysa hash'lenmeden gönderilen alanlar
if lead.fbc:
ud["fbc"] = lead.fbc
if lead.fbp:
ud["fbp"] = lead.fbp
return udBir detay daha: Kıbrıs gibi çok uluslu alıcı kitlesi olan pazarlarda
default_regionsabit "TR" olamaz. İngiltere'den gelen bir lead'in07...ile başlayan numarası Türkiye varsayımıyla ayrıştırılırsa geçersiz sayılır ya da daha kötüsü yanlış bir numara üretir. Bu yüzden formda ülke seçimini ayrı bir alan olarak tutmak, normalizasyonun doğruluğunu doğrudan etkiliyor.fbc, fbp ve external_id: Eşleşmeyi güçlendiren köprüler
E-posta ve telefon tek başına çoğu zaman yeterli olur, ama iki alan eşleşme kalitesini belirgin biçimde artırır:fbc: Reklam tıklamasıyla gelenfbclidparametresinden türetilen tıklama kimliği. Kullanıcı sitenize reklamla geldiyse_fbcçerezinde bulunur.fbp: Pikselin tarayıcıya yazdığı_fbpçerezi.
Bu değerler satış anında değil, lead oluştuğu anda yakalanmalı. Üç hafta sonra sözleşme imzalanırken kullanıcı tarayıcısında değil, satış ofisinde oturuyor. Bu nedenle form gönderiminde bu iki çerezi gizli alanlarla alıp lead kaydına yazmak, sonraki tüm offline olayların kalitesini belirliyor. Meta Lead Ads formlarından gelen lead'lerde ise platformun verdiği lead kimliğini saklamak aynı işi görür; CRM entegrasyonu senaryolarında bu kimliğin olayla birlikte gönderilmesi eşleşmeyi doğrudan kurar.
external_idise sizin CRM'deki kişi kimliğiniz. Hem piksel hem sunucu tarafında aynı değer (hash'lenmiş olarak) gönderilirse, aynı kişinin farklı olaylarını birbirine bağlamak kolaylaşır.event_id ile tekilleştirme: Aynı satışı iki kez saymamak
CAPI'de iki ayrı tekrar riski vardır:- Piksel ile sunucu çakışması:
Leadolayını hem tarayıcı pikseli hem sunucu gönderiyorsa, iki olay aynıevent_nameve aynıevent_idile gelmelidir. Meta bu ikiliyi tek olay olarak sayar. - Yeniden deneme çakışması: Ağ zaman aşımı yüzünden isteğin ulaşıp ulaşmadığını bilmiyorsanız ve tekrar gönderirseniz, aynı
event_idkorunmalıdır.
event_idrastgele üretilmemeli; olaydan deterministik olarak türetilmeli. Benim tercihim şu:def make_event_id(event_name: str, lead_id: int, stage_version: int) -> str:
return f"{event_name.lower()}:{lead_id}:{stage_version}"stage_version, fırsatın o aşamaya kaçıncı kez girdiğini tutan bir sayaç. Böylece bir müşteri gerçekten ikinci bir daire satın alırsa yeni birPurchaseüretilir, ama aynı satış için yapılan iki gönderim aynı kimliği taşır. VeritabanındakiUNIQUEkısıtı da aynı olayın kuyruğa iki kez girmesini engeller.Zaman penceresi: event_time "şimdi" değil, olayın gerçek zamanıdır
Offline satış entegrasyonunda en sık yapılan hata,event_timealanına gönderim anını yazmak. Olayın değeri, ne zaman gerçekleştiğiyle anlam kazanır; sözleşme salı günü imzalandıysa ve işçi çarşamba gönderdiyse,event_timesalı olmalıdır.İkinci önemli nokta, Meta'nın kabul ettiği geriye dönük pencere. Bu yazıyı yazarken belgeler, olayların gerçekleştikten sonra sınırlı bir süre içinde gönderilmesini istiyor ve bu süre
action_sourcedeğerine göre farklılaşabiliyor. Sınır zamanla değişebildiği için kodda sabit bir sayı gömmek yerine yapılandırmadan okuyorum ve pencereyi aşmış olayları göndermeyi denemek yerineskippedolarak işaretleyip raporluyorum:from datetime import datetime, timezone, timedelta
MAX_AGE = { # yapılandırmadan gelir; güncel değeri resmi belgeden doğrulayın
"system_generated": timedelta(days=7),
"physical_store": timedelta(days=7),
}def is_sendable(evt, action_source: str) -> bool:
age = datetime.now(timezone.utc) - evt.occurred_at
return age <= MAX_AGE.get(action_source, timedelta(days=7))Bu kontrolün pratik sonucu, satış ekibinin CRM'i zamanında güncellemesinin bir veri kalitesi konusu haline gelmesi. Sözleşmeyi on gün sonra sisteme giren bir ekip, reklam optimizasyonuna o satışı hiç kazandıramaz. Bu yüzden ben bu entegrasyonu kurarken satış ekibi için "sözleşme imzalandığı gün CRM'de kapanır" kuralını da süreç tarafında yazılı hale getiriyorum.
action_source ve olay gövdesi
Sunucudan giden olay gövdesinin iskeleti şöyle:def build_payload(evt, lead, action_source="system_generated") -> dict:
data = {
"event_name": evt.event_name,
"event_time": int(evt.occurred_at.timestamp()),
"event_id": evt.event_id,
"action_source": action_source,
"user_data": build_user_data(lead),
}
if evt.value_minor is not None:
data["custom_data"] = {
"value": evt.value_minor / 100,
"currency": evt.currency,
}
return {"data": [data]}action_sourcealanı, olayın nerede gerçekleştiğini anlatır. Web formu içinwebsite, CRM'in kendi ürettiği aşama değişiklikleri içinsystem_generated, satış ofisinde imzalanan sözleşme içinphysical_storegibi değerler kullanılabilir. Doğru değeri seçmek hem raporlamayı hem de uygulanan kuralları etkiler; bu yüzden olay sözlüğünde her olayınaction_sourcedeğerini de sabitliyorum.valuetarafında bir uyarı: Konut gibi yüksek tutarlı satışlarda gerçek sözleşme bedelini göndermek bazı ekiplerin istemediği bir şey olabilir. Bu durumda tutarlı bir "değer skalası" (örneğin ürün tipine göre sabit bir puan) kullanmak, optimizasyon sinyalini korurken hassas ticari bilgiyi dışarı çıkarmamanın bir yolu. Hangisi seçilirse seçilsin, tutarlılık önemlidir; ay ortasında yöntemi değiştirmek raporları kırar.Gönderim işçisi: Toplu istek, yeniden deneme ve hata sınıflandırma
İşçinin görevi basit görünür ama hata sınıflandırması önemli:import requests, time
def send_batch(events, leads, pixel_id, token):
payload = {"data": []}
for evt in events:
payload["data"].extend(build_payload(evt, leads[evt.lead_id])["data"])
url = f"https://graph.facebook.com/{API_VERSION}/{pixel_id}/events"
resp = requests.post(url, params={"access_token": token}, json=payload, timeout=15)
if resp.status_code >= 500 or resp.status_code == 429:
raise RetryableError(resp.text) # üstel bekleme ile tekrar
if resp.status_code >= 400:
raise PermanentError(resp.text) # kaydı failed yap, alarm üret
return resp.json()Kurallarım:
- 5xx ve hız sınırı hataları yeniden denenir; bekleme süresi her denemede artar ve
event_idaynı kalır. - 4xx hatalar (geçersiz parametre, süresi dolmuş token) yeniden denenmez. Tekrar göndermek sonucu değiştirmez, yalnızca log kirletir. Bunlar bir alarm kanalına düşer.
- Token kod içinde değil, gizli değişken yönetiminde tutulur ve süresi izlenir. Sistem kullanıcısı token'ı kullanmak, bir çalışanın hesabı kapandığında entegrasyonun sessizce durmasını engeller.
- Test olay kodu ile canlıya geçmeden önce olayların Events Manager'daki test ekranında doğru göründüğü doğrulanır.
İzin ve veri minimizasyonu
Kişisel veriyi üçüncü bir platforma, hash'lenmiş olsa bile, göndermek bir hukuki dayanak gerektirir. Türkiye'de KVKK, Avrupa'dan gelen alıcılar için GDPR bu çerçeveyi çizer. Benim teknik tarafta uyguladığım kurallar:- Lead kaydında reklam ölçümüne ilişkin izin durumu ayrı bir alan olarak tutulur ve işçi, izni olmayan kişi için olay göndermez.
- Yalnızca eşleşme için gerekli alanlar gönderilir; adres, doğum tarihi gibi alanlar "olsa iyi olur" diye eklenmez.
- İzin geri çekildiğinde, kuyruktaki bekleyen olaylar da iptal edilir.
Bu bir hukuki görüş değil; ama izin kontrolünü kodun içine bir
ifolarak gömmek, sonradan "kimin verisi nereye gitti" sorusuna cevap verebilmeyi sağlıyor.Ölçüm: Entegrasyon gerçekten çalışıyor mu?
Kurulumdan sonra baktığım üç gösterge var:- Eşleşme kalitesi: Events Manager'daki olay eşleşme göstergesi. Düşükse ilk şüpheli normalizasyondur.
- Gecikme dağılımı:
occurred_atile gönderim zamanı arasındaki fark. Satış ekibinin CRM'i geç güncellemesi burada hemen görünür. - CRM ile panel karşılaştırması: Aylık kapanan satış sayısı ile Meta'nın aldığı
Purchasesayısı arasındaki fark. Birebir tutması beklenmez, ama fark aniden açılırsa token, izin veya şema tarafında bir şey bozulmuştur.
Sıkça Sorulan Sorular
Piksel zaten kurulu, neden ayrıca CAPI gerekiyor?
Piksel yalnızca tarayıcıda olan olayları görür. Telefonla kapanan, satış ofisinde imzalanan ya da haftalar sonra gerçekleşen satışlar tarayıcıda olmaz. CAPI, bu olayları CRM'den doğrudan göndermeyi sağlar.E-postayı hash'lemeden göndersem Meta kendisi hash'lemez mi?
Bazı resmi kütüphaneler hash işlemini kendisi yapar, ama kendi kodunuzla gönderiyorsanız normalizasyon ve hash sizin sorumluluğunuzdadır. Kontrolü elde tutmak, hatayı ayıklamayı da kolaylaştırır.Aynı satışı yanlışlıkla iki kez gönderirsem ne olur?
Aynıevent_nameveevent_idile gönderildiyse tekilleştirilir. Farklı kimlikle gönderildiyse iki satış sayılır; bu yüzden kimliği deterministik üretmek önemlidir.Satış on gün sonra CRM'e girildi, yine de gönderebilir miyim?
Meta'nın kabul ettiği geriye dönük pencereyi aşmışsa olay reddedilir. Güncel sınırı resmi belgeden kontrol edin ve asıl çözümü süreçte arayın: satış, gerçekleştiği gün CRM'e girilmeli.Gerçek sözleşme bedelini göndermek zorunda mıyım?
Hayır. Tutarlı bir değer skalası da optimizasyon için yeterli sinyal üretebilir. Önemli olan, seçilen yöntemin zaman içinde değişmemesi.Bu entegrasyon küçük ekipler için fazla karmaşık değil mi?
Kuyruk tablosu, normalizasyon fonksiyonu ve bir gönderim işçisi birkaç yüz satır kod demek. Karşılığında reklam algoritması form dolduranları değil, satın alanları öğrenmeye başlar. Lead hacmi düşük ama satış değeri yüksek sektörlerde bu fark özellikle belirgin.Koray Yalçın — lead yönetimi, CRM mimarisi, dijital pazarlama ve gayrimenkul teknolojileri (PropTech) üzerine çalışıyorum. CRM'den reklam platformlarına geri bildirim kurarken sizi en çok hangi adım zorladı? Yorumlarda konuşalım.#backend #crm #api #marketing #software #coding #development #engineering #inclusive #community
CRM'de kapanan satışı Meta Conversions API'ye geri bildirmek: Hash, event_id ve zaman penceresi üzerine geliştirici notları -
Sunday Morning Reading
Writing a blog is an interesting experience. So is reading them. The best blogs are the ones where the person behind the keyboard shines through. You can say it takes courage to put yourself and your opinions out there. You would be correct. A lot of that got diminished when social media took over because of its hit and run nature. But blogs and the writers behind them are still there and surface now and again. Today’s Sunday Morning Reading features a few along with a few other tricks and treats. Hope you check them and the rest of the links out.
Good writing stands out. Even on the Internet where it comes in small waves and ripples, subsequently washed away by more of the same, or often overwhelmed by the slop running alongside threatening to take it over. David Todd McCarty’s A Stream Has No Memory isn’t about that necessarily, and yet it is. All things flow.
As I mentioned, personal blogging took a hit when the age of social media dawned. Yet, those that still exist, though not always as prolific, still provide insight when a writer allows you to peek into deeper waters. In many ways putting yourself out there, regardless of where, can easily become a personal hell. There’s been quite a controversy eddying about in tech circles about some who loudly condemned what was formerly Twitter reversing course and just as publicly announcing that they are returning. To each their own personal hell, I guess. I’ve stated my feelings about that here and here. Noted developer Marco Arment took to his blog with a post simply and aptly titled Community. It isn’t about what X marks the spot, it’s about what I believe deep down we all search for when we choose to share ourselves in our writing and our creative work. It can be lonely even with a magnitude of followers in whatever personal hell you choose to put yourself into.
Jason Snell links to an excellent post by Cory Doctorow called Critique And Writing. Yes, it’s about AI and folks using it to generate editorial feedback, but it’s about so much more. We develop critical thinking by critiquing the work of others who work in the same field, whether it be writing or other disciplines. I had an acting professor once tell the class that the way we responded to the work of others told him more about how we were developing (or not) as actors as the work we ourselves did onstage.
In the category of things we all share but wish we didn’t Neil Steinberg takes on scams and their persistent and constantly replicating existence in I Look Forward To Reviewing Your Proposal And Learning About The Quest For Pie.
Natasha MH takes a look at perhaps the year’s most controversial film, Digger, in Hail The Conquering Heroes. That film is becoming a personal measuring stick for me as to who sees the world we live in as I do and who doesn’t.
Halloween is upon us. With grandkids that’s quite a treat. But it can also be tricky. I’m headed there next weekend because my grandson has convinced us that we have to go trick-or-treating with him and his sister. He’s chosen for me to be costumed as a T-Rex. (Wearing costumes is my own personal hell.) Regardless of my escapades, I marvel at all of the decorations that abound and proliferate in yards up and down every block of every town rendering them all somewhat meaningless. Rex Huppke takes on the topic in America Has An Addiction To Giant Halloween Skeletons.
And if Halloween spirits swirling amongst all of the evil things going on in the real world aren’t enough to scare the beejeebus out of you give a read to Max Seddon’s piece The Putin Whisperers about three men who worked to stop Putin from unleashing nuclear Armageddon. Some things are just damn scary.
All things flow.
(Image from The Cleveland Museum of Art on Unsplash.)
Thanks for reading. Feel free to subscribe if you want. It’s free. If you’re interested in just what the heck Sunday Morning Reading is all about you can read more about the origins of Sunday Morning Reading here. If you’d like more click on the Sunday Morning Reading link in the category column to check out what’s been shared on Sunday’s past. You can also find more of my writings on Medium at this link, including in the publications Ellemeno and Rome. This site does not use affilate links.
#ai #blog #blogging #books #Community #Culture #Internet #life #Movies #russia #SocialMedia #SundayMorningReading #Tech #ukraine #Writing -
Previews, Pre-Season, Betas, and Opening Nights
There’s an old saying in the theatre biz. No show is ever really ready on opening night. It’s a cliché that has seen it’s time pass in the big money commercial circuit because so many producers run lengthy preview weeks, charging essentially, but not quite, full price to avoid reviewers publishing their criticisms until the show is officially open. The preview process began lengthing after the days of out-of-town tryouts came to an end, although we see that still happening occasionally as larger regional theatres will debut a work, allowing it to still be worked on, hoping that it will one day make it to Broadway.
There was a famous production of Eugene O’Neil’s play Hughie, starring and directed by Al Pacino, that ran in previews for almost a month before finally opening. That led to a critic from Daily Variety breaking the only after opening night embargo a week early since the announced limited run would end up with less “real” performances than those in previews after the show officially opened. The show would go on to extend the run a couple of times.
In smaller circuits the cliché still lives on, simply because of a lack of resources to run many preview performances in front of audiences to really gauge reaction before it officially opens. A show can look great in final dress rehearsals, but it’s never complete until there’s a paying audience of strangers sitting in the dark to tell if it works or not. The ever-present lack of time still breathes life into the cliché in ways that offer both hope and anxiety behind opening night curtains around the world.
In the professional sports world teams play in a pre-season or spring training games that don’t matter while the players tune up for the real thing. Although in most of those types of meaningless games it’s really more like watching players audition than it is anything else. Occasionally a budding star emerges, but that’s atypical. Early “real” season games that do count (at full price) are when teams find out what they have, leading knowledgeable sports viewers knowing when it is time to pay real attention to a team’s chances or not.
Those are two interests in my life. I’m a theatre professional (and geek) and I watch sports. Another is my interest in tech. In tech we have betas. Or we used to, when that was mostly for software. Now we’re just in previews, pre-season, or perpetual betas forever for both software and hardware. Which is somewhat understandable, yet weird, perhaps ironic, but ultimately a joke on the paying public, given the pace in which things are always advancing in tech, including the pace and price of advancement.
We never seem to reach opening night, opening day or the end of a beta period in tech. Instead products and software are released incomplete, occasionally followed immediately by “leaks” that suggest the company that just took your money for it’s latest best product ever is working on fixing the things they knew were wrong for the next version when they released the product you just payed for.
But you’re going to love it.
It’s easier to swallow with software. It’s a bigger pill that sticks in the craw with hardware.
It used to be that betas were for working out bugs. They still are to a degree, but now they’re just the next show in a never-ending season, or the latest minor-league call up. But you still pay full price for the game when the team needs to put a not ready for the big leagues pitcher on the mound just to fulfill its obligation to play the announced season.
You can argue that there’s nothing wrong with the way things have evolved in tech because the financial equations are different. It requires a substantial upfront investment to create, produce and deliver new technology. You’d be mostly wrong, but you can argue it. Most of the costs in show biz happen upfront before a show even gets close to an audience, hopefully a large enough one in a long enough run to recoup the initial investment. It is a different equation in sports.
The release of Apple’s iPhone Duo strikes me as an interesting entry in this evolution of consumer dynamics. Soon, perhaps too soon, before the product was released to the general public, leaks popped out that Apple was working on tweaks to two of the major criticisms of the device for the next generation — a larger model and adding FaceID. That followed criticism from reviewers.
In general, most tech reviews I read, watched, or listened to made it very clear that the iPhone Duo was a first generation device with some rough edges that wasn’t for everyone, especially at the entry price. I can’t judge those reviews myself since I haven’t seen the product, but they mostly seemed very similar and to my mind fair. Some, sounding more like theatre critics or sport writers I’ve known, were more harsh, delivering criticism that might have prompted a closing notice being posted before intermission or an early game benching.
Here’s where my three interests diverge a bit. In theatre the show can close early if it’s savaged or not enthusiastically endorsed by reviews. In sports a pro team can retool a bit by trading or signing free agents midseason. Tech companies have to play out the run with tech hardware until the next generation is ready.
Given the leaks following the reviews I find it sort of funny that I’m in a place of feeling a bit sorry for the carriers that are offering great deals on the iPhone Duo subsidized by a three year contract. That’s a tough sell to anyone who pays attention, though admittedly most won’t if they’re hot to trot for the new shiny folding phone from Apple.
It’s my hunch, and only a hunch, that Apple knew these criticisms were coming. Even so, it’s one thing to prepare the next version hoping to make changes that advance a platform, it’s another to make them in reaction to negative press once the product is unveiled. It sets you up in the next round for being congratulated for fixing what was wrong the last time.
In the theatre if a joke doesn’t land, you can replace the joke in previews. In sports you bench a player or fire a coach. With tech hardware it’s not that easy changing things before it becomes a punch line. (See the Vision Pro.)
My second hunch, only a hunch, is that the iPhone Duo will eventually become a successful part of Apple’s lineup and get past what feels like a rough opening. I don’t think it will enter into Vision Pro punchline territory. Critics of all human endeavors need something to criticize as much as companies need to produce the next thing. It’s a symbiotic relationship that feeds on itself. And the always distracted general public has short-term memory bordering on amnesia.
It’s my wish that tech companies, like theatre companies and sports teams, would figure out a better path to the success they seek. Sure, you might be able to fool some of the people all of the time. But for the most part folks figure it out on their own. Some of the time. And that some of the time is what everybody on the producing end of things counts on.
Thanks for reading. You can subscribe to this blog if you care to. You can also find more of my writings on a variety of topics on Medium at this link, including in the publications Ellemeno and Rome. I can also be found on social media under my name as above. This site does not use affilate links.
#Apple #iPhone #iPhoneDuo #reviews #Sports #Tech #technology #TheaterOfTheMind #Theatre #Writing