◉ANTIGRAVITY LABJP
Articles/Agents & Manager
◈ Agents & Manager/2026-07-06Advanced

When Parallel Agents Ran the Same Task Twice and Quietly Doubled the Bill — Field Notes on Measuring and Stopping Duplicates

The bill for our parallel agents came in about 1.9x higher than expected — because multiple workers were running the same task twice. These are field notes on measuring the duplication, stopping it with idempotency keys, and attributing cost per task.

multi-agent50idempotency11cost management5production71Antigravity376

✦ Premium Article

I opened the monthly bill and stopped scrolling. Volume was roughly flat, but the number was about 1.9x what I expected. Not a single alert had fired. Every request in the logs had completed successfully.

It took half a day to find. Of the three workers I was running in parallel, two were picking up the same task independently, each deciding it was theirs, and each running it to completion. The outputs matched, so everything looked correct. Underneath, generation charges were quietly stacking up twice.

These are field notes on catching that silent double-execution through measurement, stopping it with idempotency keys, and attributing cost per task. The setup assumes you delegate a batch of tasks across multiple agents — the way Antigravity's Managed Agents work. I built it as a layer that doesn't depend on a specific SDK, so it ports to the Gemini API or your own workers.

Why Duplication Happens Without Raising an Error

What makes double-execution nasty is that it throws no exception. Both workers succeed, both return correct results. The orchestrator simply discards or overwrites the second result, and the fact that the work ran twice leaves no trace.

The root cause is that an LLM won't explicitly decline "this isn't mine." Write the responsibility boundary loosely and several workers will each claim the same request as their own.

SymptomWhat you seeWhat you don't
Double-runCorrect output, no errorThe same task billed twice
DropCounts don't add upEvery worker judged it "out of scope" and left it
LoopHigher latencyWorkers bouncing the boundary back and forth

The first thing that helped was writing each worker's scope down to what it must NOT do, not just what it does.

# ❌ Ambiguous boundary (breeds duplicates and drops)
You are a data-processing agent. Create reports as needed.
 
# ✅ Name the out-of-scope work and hand it back
You are a worker dedicated to "JSON -> schema conversion".
In scope: convert the received JSON to the given schema and return it.
Out of scope: saving, sending, report generation, re-delegating to other workers.
If out-of-scope input arrives, return only {"status":"out_of_scope"} with no body
and hand it back to the orchestrator. Do not cover for it yourself.

But clarifying the prompt only makes duplication less likely. When a source of variability runs in parallel, you need a structural mechanism to actually stop it.

Making Duplication Visible With an Execution Ledger

Before stopping it, count it. If you don't record which task ran how many times, you can't judge whether a fix worked either.

The crux is how you define task identity. I built a fingerprint from the semantic body of the input — the normalized arguments. The trick is to strip out values that change on every run, like timestamps and execution IDs, before normalizing.

import hashlib
import json
import time
 
def task_fingerprint(task_type: str, payload: dict) -> str:
    """Key on semantic identity by dropping values that change per run."""
    volatile = {"request_id", "timestamp", "attempt", "trace_id"}
    stable = {k: v for k, v in payload.items() if k not in volatile}
    # Fix key order for a stable hash
    canonical = json.dumps(stable, sort_keys=True, ensure_ascii=False)
    digest = hashlib.sha256(f"{task_type}:{canonical}".encode()).hexdigest()
    return digest[:16]
 
 
class ExecutionLedger:
    """Records run counts per task. store is a thin KV wrapper (e.g. Redis)."""
 
    def __init__(self, store):
        self.store = store  # provides get/incr/expire
 
    def record(self, fp: str, worker_id: str) -> int:
        key = f"ledger:{fp}"
        count = self.store.incr(key)          # increment run count
        self.store.expire(key, 60 * 60 * 24)  # let it age out in 24h
        self.store.sadd(f"{key}:workers", worker_id)
        return count  # >= 2 means this task was run more than once

After wiring this into production for about a week, the duplication rate came into focus. Roughly 18% of all tasks ran two or more times, and nearly all of it concentrated in two specific task types. I had assumed it was an "every now and then" problem, so that 18% was a genuine surprise.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦An execution ledger that detects double-runs via task fingerprints
✦A SET NX claim-before-run idempotency pattern that stops double billing
✦Per-agent, per-task cost attribution that catches billing anomalies early
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $15 for lifetime access
View Membership →

Related Articles

◈ Agents & Manager2026-04-27
Five Paths to Sell AI Agents Built on AgentKit 2.0 — How Indie Developers Should Pick a Distribution Channel
AgentKit 2.0 lets a solo developer ship a real, useful AI agent. The hard question is where to sell it. This article walks through five distribution paths — marketplaces, direct sales, SaaS embedding, productized consulting, and subscription agents — with the trade-offs that matter.
◈ Agents & Manager2026-04-14
Build an AI Agent SaaS with Antigravity × AgentKit 2.0 × Stripe — A Complete Implementation Guide for Solo Developers
How to build a subscription AI agent SaaS with AgentKit 2.0, Stripe and Antigravity. Architecture, billing, Webhook idempotency, production deployment — plus the Redis concurrency-slot bug that quietly locks out your heaviest users.
◉ Antigravity2026-04-25
Designing Antigravity Retry for Production — Idempotency, Backoff, Cost Ceilings, and Failure Triage
A production blueprint for Antigravity agent retry: idempotency, exponential backoff, token-budget ceilings, failure triage, and resumable checkpoints.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links