ANTIGRAVITY LABJP
Articles/Editor View
Editor View/2026-08-01Advanced

The Date Column Was the Most Expensive Part of My Sales CSV — Measuring What Attachments Really Cost

2.4.3 lets you attach .json, .md, and .csv files directly. I rendered the same table eight ways, priced every column in tokens, and boiled it down to a 1,062-token digest. Every number here came from a run on my own machine.

Antigravity346context design4tokens2CSVmeasurement5solo development3

Premium Article

I was watching the context meter in the side pane while attaching a sales report covering June onward. 1,730 rows, 127 KB. Small, as text goes. The meter still dropped visibly before I had finished typing my question.

At the time I just cut the range in half and sent it again. What stayed with me was the thought I had the next morning: the same content, written a different way, might cost twice as much or half as much. If so, the thing to trim wasn't rows — it was formatting.

Working solo, small frictions like this come back on the same day every week. Re-slicing a date range takes half a minute, which is short enough to ignore and long enough to dull the decision behind it.

Version 2.4.3 added .json, .md, and .csv attachments to the input field, each with its own badge, so you can hand over a file instead of pasting its contents. More options means the choice of representation has moved onto my side of the table.

This is the record of measuring that choice instead of guessing at it.

One note up front: I can't publish the actual report, so every number below comes from a table with identical columns and comparable size, generated from a fixed seed. The generator is included, so you can confirm the same figures on your own machine.

About the tokenizer

I measured with OpenAI's tiktoken (o200k_base). That is not the tokenizer Gemini uses, so you cannot convert these absolute numbers into a bill.

As a relative index, though, it holds up. Running the same measurement through cl100k_base produced reduction ratios of 0.476 and 0.483 — essentially identical. Differences caused by format and column design are far larger than differences between tokenizers.

Read the ratios and percentages as the finding; treat absolute counts as a rough scale.

The table under test

Same column layout as an App Store Connect sales report: 62 days across 9 countries and 4 SKUs, with some zero-unit rows dropped, giving 1,730 rows.

# mkdata.py — generate the measurement data from a fixed seed
import csv, random, datetime, os
random.seed(20260801)
 
countries = ["JP","US","GB","DE","FR","KR","TW","CA","AU"]
skus = [
    ("WLP.PRO.YEAR",   "Wallpaper Pro (Yearly)"),
    ("WLP.PRO.MONTH",  "Wallpaper Pro (Monthly)"),
    ("CALM.REMOVEADS", "Calm Sounds Remove Ads"),
    ("CALM.PACK.02",   "Calm Sounds Pack 02"),
]
rate  = {"JP":1.0,"US":150.0,"GB":190.0,"DE":163.0,"FR":163.0,
         "KR":0.11,"TW":4.7,"CA":110.0,"AU":98.0}
cur   = {"JP":"JPY","US":"USD","GB":"GBP","DE":"EUR","FR":"EUR",
         "KR":"KRW","TW":"TWD","CA":"CAD","AU":"AUD"}
base  = {"JP":40,"US":22,"GB":6,"DE":7,"FR":4,"KR":9,"TW":5,"CA":3,"AU":3}
price = {"WLP.PRO.YEAR":3800.0,"WLP.PRO.MONTH":480.0,
         "CALM.REMOVEADS":320.0,"CALM.PACK.02":250.0}
mix   = {"WLP.PRO.YEAR":0.12,"WLP.PRO.MONTH":0.46,
         "CALM.REMOVEADS":0.28,"CALM.PACK.02":0.14}
 
d0 = datetime.date(2026, 5, 31)
rows = []
for i in range(62):
    d = d0 + datetime.timedelta(days=i)
    wk = 1.18 if d.weekday() >= 5 else 1.0          # weekends run a little hotter
    for c in countries:
        for sku, name in skus:
            lam = base[c] * mix[sku] * wk
            units = max(0, int(random.gauss(lam, lam * 0.45)))
            if units == 0 and random.random() < 0.55:
                continue                             # some zero rows never appear
            proceeds = units * price[sku] * 0.70 / rate[c]
            rows.append({
                "date": d.isoformat(),
                "country_code": c,
                "product_sku": sku,
                "product_name": name,
                "device_type": random.choice(["iPhone", "iPad"]),
                "units_sold": units,
                # FX conversion leaves long decimals behind — very common in real exports
                "developer_proceeds": repr(round(proceeds, 10)),
                "currency_code": cur[c],
            })
 
p = os.path.expanduser("~/lab/sales.csv")
os.makedirs(os.path.dirname(p), exist_ok=True)
with open(p, "w", newline="") as f:
    w = csv.DictWriter(f, fieldnames=list(rows[0].keys()))
    w.writeheader(); w.writerows(rows)
print("rows:", len(rows), "bytes:", os.path.getsize(p))
# => rows: 1730 bytes: 127536

The defining feature is a developer_proceeds column full of values like 24181.8181818182. Any report that passes through currency conversion looks like this. It matters later.

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
A measured comparison of the same 1,730-row table rendered as CSV, TSV, Markdown, JSON, and YAML — padded Markdown is the priciest, and columnar JSON is nearly free
A script that drops one column at a time to price each column by difference; in a sales export the date column cost more than the money column
A 1,062-token digest that replaces the full table, plus the failure mode where a digest quietly lies to you (mixed units in one numeric column)
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

Editor View2026-07-17
One Space in a Path, and Nine Commands Reported Success While Counting the Wrong Place
A single space in a workspace name sends agent-written commands somewhere else, quietly. Measurements across eleven unquoted-path forms, and the entry-point script that closes the boundary in one cd.
Editor View2026-07-16
Three Ways to Hand 4,000 Lines of Logs to an Agent — Paste, .txt Attachment, or @ Reference
v2.3.0 added plain-text attachments, which means there are now three ways to hand a long log to an agent — and a new question about which one to pick. Here is how I trim, measure, and decide, with the scripts I actually run.
Editor View2026-07-16
Your UI Is in Japanese. Your Commit Log Isn't.
Setting your editor's display language does nothing for the language your agents write into the repository. Here is what six weeks of unattended runs actually produced, how to pin output language per audience, and a gate that catches the drift mechanically.
📚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 →