ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-07-02Intermediate

Before You Let an Agent Own Your Tests — Deciding How Fixtures and Seed Data Live

Agents will happily edit test data until the tests pass. A practical defense built on fixture ownership, deterministic seeds, and anonymized subsets of production data, with working scripts.

antigravity409app-dev45test-datafixturesquality-assurance3

Premium Article

I handed a failing test suite to an Antigravity agent and asked it to fix things. A few minutes later everything was green. The diff told the real story: the application code was untouched, and fixtures/users.json had been rewritten to match the assertions. The agent had made the tests pass by editing the test data.

No malice involved. The agent took the shortest path to the goal I gave it — "make the tests pass." The actual failure was mine: I had delegated testing without deciding anything about how test data should be handled.

Since then I keep three rules pinned in every project: fixture ownership, seed determinism, and a fixed procedure for carving subsets from real data. Here they are, in order.

Rule 1 — take fixture ownership away from the agent

The first change was declaring fixtures/ read-only for agents. If the agent believes an expected value must change, it reports a proposal instead of editing. One paragraph in the Guide skill goes a surprisingly long way:

## Test data policy
- Files under fixtures/ are read-only
- If you conclude an expected value must change, do not edit it;
  report a "fixture change proposal" with your reasoning

Guide skills are advisory, though, not enforcement. So a mechanical backstop lives in CI: reject any commit that touches fixtures and application code at the same time.

#!/usr/bin/env bash
# fixture-guard.sh — detect simultaneous fixture/src changes
CHANGED="$(git diff --cached --name-only)"
FIXTURE_TOUCHED=$(echo "$CHANGED" | grep -c '^fixtures/' || true)
SRC_TOUCHED=$(echo "$CHANGED" | grep -c '^src/' || true)
 
if [ "$FIXTURE_TOUCHED" -gt 0 ] && [ "$SRC_TOUCHED" -gt 0 ]; then
  echo "❌ fixture and src changes must be separated"
  echo "   fixture edits need their own commit with the reason in the message"
  exit 1
fi
exit 0

Changing fixtures is not forbidden — legitimate updates follow spec changes all the time. What is forbidden is quietly moving the goalposts in the same hand that edits the code. Forced into a standalone commit, a fixture change always crosses a reviewer's eyes.

Rule 2 — generate seeds deterministically

Tests written by agents tend to come with improvised test data: random names and dates conjured inline. That is a factory for flaky tests that pass on Tuesday and fail on Thursday.

The fix is to centralize data creation in one generator script with a pinned seed:

// scripts/generate-fixtures.mjs
import { faker } from "@faker-js/faker";
import { writeFileSync } from "node:fs";
 
faker.seed(20260702); // pinned seed — identical output on every run
 
const users = Array.from({ length: 50 }, (_, i) => ({
  id: `u${String(i + 1).padStart(4, "0")}`,
  name: faker.person.fullName(),
  email: faker.internet.email().toLowerCase(),
  createdAt: faker.date
    .between({ from: "2025-01-01", to: "2026-06-30" })
    .toISOString(),
  plan: faker.helpers.arrayElement(["free", "pro", "premium"]),
}));
 
writeFileSync(
  "fixtures/users.json",
  JSON.stringify({ schemaVersion: 3, users }, null, 2)
);
console.log(`generated ${users.length} users (schemaVersion 3)`);

A pinned seed gives you a tamper check for free: regenerate and diff. If the file in the repository no longer matches the generator's output, someone — usually an agent — edited it by hand.

The schemaVersion embedded in the fixture lets tests validate their assumptions. When versions disagree, I skip with a warning rather than fail, which keeps migration periods quiet.

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 real case of an agent editing fixtures to force green, and the CI guard that catches it
A deterministic seed script with faker that regenerates identical test data every run
A four-stage procedure and masking table for safely carving anonymized subsets from production data
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

App Dev2026-06-30
When Every Antigravity-Written Test Is Green but the Same Bug Comes Back — Field Notes on Measuring Hollow Assertions
Your AI-written tests all pass, coverage is high, yet the same defect returns to production. The cause is over-mocking and tautological assertions. These are field notes on using mutation testing as ground truth to measure what your tests actually protect, and to fix it operationally.
App Dev2026-06-28
Adding Mediation Partners Quietly Starved My iOS Attribution — Reconciling SKAdNetwork IDs Across Four Apps
I added mediation partners but iOS revenue barely moved — the cause was missing SKAdNetwork IDs in Info.plist. Here is how I reconciled SKAdNetworkItems across four apps, using an Antigravity agent as the matcher while keeping the revenue decisions by hand.
App Dev2026-06-25
An Agent Granted 'Watch an Ad to Unlock a Wallpaper' Entirely Client-Side — Re-Verifying Reward Grants with AdMob SSV
I asked an Antigravity agent to wire up 'watch a rewarded ad to unlock a wallpaper,' and it returned an implementation that wrote the unlock flag client-side only. Here is why that is not enough, how I re-verified the reward grant with AdMob server-side verification (SSV), and how I stopped double grants too.
📚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 →