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-agent49idempotency11cost management5production71Antigravity313

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 $10 for lifetime access
View Membership →

Related Articles

Agents & Manager2026-03-14
Multi-Agent Orchestration with Antigravity — A Production Implementation Guide
Build production-grade multi-agent systems using Antigravity. Covers orchestrator/worker separation, DAG-based task management, parallel execution, retry logic, and cost optimization with real Python code.
Agents & Manager2026-06-19
Your Antigravity Sandbox Isolates Multi-Agents Less Than You Think — Notes on Containing the Blast Radius
An Antigravity sandbox gives you the feeling of isolation, but isolation leaks through three real gaps: shared volumes, over-broad allowed domains, and approval fatigue. Field notes on plugging the leaks, containing the blast radius by design, and proving isolation holds with tests.
Agents & Manager2026-06-17
Making Managed Agent Batches Safe to Re-run: Idempotency and Checkpoints
Running overnight batches on the Antigravity 2.0 Managed Agents API makes recovery from partial failure unavoidable. Starting from a duplicate-post incident, I share the implementation of idempotency keys, a checkpoint store, and resume logic, with real numbers from solo operations.
📚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
See all →