field notes from the satus team.
- 4 min
How satus 0.3.11 decides a database is too full to seed
Before any write, satus 0.3.11 counts rows in every user table in the database and refuses above 10,000 with exit 11. What it counts, what it skips, and why.
- ·seeding
- ·postgres
- ·safety
- ·ci
- 5 min
Multi-column uniques, and why satus v0.x skips them
satus 0.3.11 reads only single-column UNIQUE constraints. It skips multi-column constraints and unique indexes, and a run that violates one is rolled back.
- ·seeding
- ·postgres
- ·constraints
- ·unique
- 5 min
What satus 0.3.11 checks before a write, and how to keep order totals correct in Postgres
satus 0.3.11 checks foreign keys, types and NOT NULL before a write. It does not check totals or CHECK constraints. Postgres enforces CHECKs on insert.
- ·seeding
- ·postgres
- ·constraints
- ·generated-columns
- 7 min
pg_dump snapshots as test fixtures
Generate once, dump the rows, restore them between test runs. The commands, two pg_dump defaults that make a fixture churn, and a restore that half-loads.
- ·seeding
- ·testing
- ·fixtures
- ·postgres
- ·pg_dump
- 7 min
Fixtures vs generation, and when each wins
A hand-written fixture passes every test until the first migration. Generated data survives the migration and cannot promise the same row twice.
- ·seeding
- ·testing
- ·fixtures
- ·postgres
- ·cli
- 6 min
Free tier, priced honestly
Why the free tier is 25 rows across 5 tables, why those 5 tables are never arbitrary, and the two integers that are the whole difference between Free and Pro.
- ·pricing
- ·product
- ·cli
- 5 min
How the dry-run cost estimate is calculated
A 125-row dry run is quoted at two cents. Three measured runs cost seven hundredths of a cent. The estimator over-quotes by 31x; this post shows the arithmetic.
- ·llm
- ·cost
- ·cli
- ·openai
- ·telemetry
- 6 min
Structured output from Claude without a JSON parser
How satus forces typed rows out of the Messages API with tool_choice, how that differs from OpenAI's json_schema, and the Anthropic feature that came later.
- ·llm
- ·anthropic
- ·openai
- ·structured-output
- ·cli
- 5 min
The cycle-breaking heuristic we documented and never shipped
In May we published a four-rule heuristic for choosing which foreign key to defer. Checked against the shipped binary, three of the four rules do not exist.
- ·postgres
- ·foreign-keys
- ·audit
- ·cli
- 4 min
v0.3.11: two claims the code did not support
Run telemetry is now opt-in, as our security page said. Primary keys come from pg_catalog, so a read-only CI role no longer gets a false green from --dry-run.
- ·release
- ·cli
- ·privacy
- ·postgres
- 9 min
information_schema is privilege-filtered, and it made our CI gate lie
A role with SELECT on every table still sees zero constraints in information_schema. Measured on PostgreSQL 16.13, with the bug it exposed in our dry-run gate.
- ·postgres
- ·catalogs
- ·introspection
- ·privileges
- ·ci
- 2 min
v0.3.10: the 24-hour license grace is now real
satus 0.3.10: activation stores the key, generate re-verifies stale verdicts, and a canceled subscription loses paid caps within 24 hours.
- ·release
- ·cli
- ·licensing
- 4 min
v0.3.9: the safety feature you couldn't turn off
Yesterday's safety guard had no escape hatch in the GitHub Action. Plus exit code 10, and what a line-by-line audit of our own docs turned up.
- ·release
- ·cli
- ·github-actions
- ·docs
- 5 min
v0.3.8: the safety guard we had already written about
satus 0.3.8 implements the 10,000-row production guard our docs have described since v0.3.x. It was documented, linked, and explained. It was never in the code.
- ·release
- ·cli
- ·postgres
- ·safety
- 6 min
v0.3.7: five bugs, four of them silent
satus 0.3.7 fixes identity columns, non-PK FKs, out-of-set TRUNCATE, cost mismatch, and telemetry that sent table names, schema names, and error text.
- ·release
- ·cli
- ·postgres
- ·privacy
- 2 min
v0.3.6: one fix, for a footgun we stepped on ourselves
satus 0.3.6 normalizes ANTHROPIC_BASE_URL so both the SDK convention (no /v1) and the previous satus convention (with /v1) work. No other changes.
- ·release
- ·anthropic
- ·cli
- 7 min
Triggers I have loved and hated
Audit, denormalization, and validation triggers each break a Postgres seed run differently. What actually happens, measured on PostgreSQL 17.9.
- ·postgres
- ·triggers
- 7 min
The schema I couldn't reproduce
Schema reproduction is our hardest maintenance task. The two bugs that took longest to reproduce, and the four artifacts we now use to shorten the loop.
- ·support
- ·tooling
- ·postgres
- 6 min
Postgres extensions that trip up seeders
PostGIS wants valid geometries. pgvector wants meaningful embeddings. pgcrypto wants real ciphertext. None of the three accept random bytes.
- ·postgres
- ·extensions
- 5 min
What a bad profile looks like
Three profile drafts we threw away before shipping saas, ecommerce, and b2b. Too many knobs, distributions that did not compose, vertical leaks.
- ·profile
- ·methodology
- ·anti-pattern
- 8 min
Seeding Stripe-shaped data without Stripe
How to fill a billing schema with realistic Customer, Subscription, Invoice, and Charge rows locally, so dashboards render without touching test-mode Stripe.
- ·billing
- ·stripe
- ·patterns
- 7 min
When UUIDs aren't the answer
UUIDv7 reopened the primary-key debate. What v7 fixes, what it doesn't, and when bigserial or a composite key is still the right choice in Postgres.
- ·postgres
- ·primary-keys
- 12 min
What pg_dump doesn't tell you about your own schema
pg_dump is a backup tool, not a schema description. Three things it omits or reorders, and why a seeder should read pg_catalog directly instead.
- ·postgres
- ·introspection
- ·pg_dump
- 4 min
v0.3.5: automated npm publishing, two correctness fixes
satus 0.3.5 adds tag-triggered npm publishing with provenance, restores deferrable-FK detection, and makes the Action selftest use the in-repo CLI.
- ·release
- ·ci
- ·github
- ·npm
- 6 min
v0.3.3: the GitHub Action, and opt-in failure fingerprints
satus 0.3.3 ships a composite GitHub Action that wraps the CLI for PR-preview databases, plus opt-in schema-shape fingerprints for the v0.4.0 eval set.
- ·release
- ·ci
- ·github
- ·telemetry
- 10 min
Generated columns are load-bearing now
Postgres GENERATED columns became infrastructure with STORED in PG12 and VIRTUAL in PG18. What that means for introspection, INSERT order and seeders.
- ·postgres
- ·generated-columns
- ·schema
- ·seeding
- 12 min
Profile design 101: pick distributions, not values
How we add a new vertical to satus: name the distributions and correlations first, and only then sample values. An internal design doc, published.
- ·profile
- ·methodology
- ·distributions
- ·postgres
- ·seeding
- 7 min
Roadmap: v0.3.3 ships the GitHub Action, and v0.5 becomes v0.4
What the next satus release will and will not do, why the GitHub Action is a 0.3.x patch and not a 0.4 line item, and how the version numbers shift.
- ·roadmap
- ·ci
- ·github
- ·release
- 5 min
The 1am deploy that only failed in prod
A field note on why a query that ran in 4ms on a seeded dev database stalled the moment it hit real cardinality, and what the planner was actually looking at.
- ·postgres
- ·planner
- ·performance
- ·seeding
- 8 min
Arrays vs junction tables: when Postgres arrays are a smell
Three cases where a Postgres array column fits, and four signs that a junction table is the better design.
- ·postgres
- ·modeling
- ·seeding
- 15 min
Inside the saas-subscriptions profile: MRR, churn, and the dunning death spiral
Subscription lifecycles, plan changes, failed payments and undocumented states. What the satus saas-subscriptions profile recommends and what it leaves to you.
- ·profile
- ·saas
- ·billing
- ·postgres
- ·seeding
- 10 min
Seeding into a multi-tenant schema without leaking tenants
Seed data leaks across tenants through shared lookup tables, FK chains that drop tenant_id, and RLS bypassed by a superuser connection. What satus does.
- ·postgres
- ·multi-tenant
- ·rls
- ·seeding
- ·security
- 7 min
Agent mode, postponed to v0.5
Why satus is shipping an opt-in agent mode in v0.5 instead of v0.3, what it will and will not do, and how a 90-day evidence window shapes the design.
- ·roadmap
- ·agents
- ·design
- ·postgres
- 9 min
Enum types that grew up
How Postgres enum types evolve in real schemas, why ALTER TYPE ADD VALUE is harder than it reads, and how satus picks realistic distributions over them.
- ·postgres
- ·enums
- ·schema
- ·seeding
- 5 min
v0.3.0: Anthropic as a first-class provider, and machine-readable output
Anthropic joins OpenAI as a peer provider via tool-use forcing. A new --json flag prints one snake_case object for CI. Token counts are stored with cost.
- ·postgres
- ·satus
- ·release
- ·anthropic
- ·openai
- ·cli
- 4 min
A $0 dry-run that catches FK and constraint bugs before the LLM call
satus 0.3 ships an offline --dry-run that simulates LLM output and validates against your live Postgres metadata. No API key, no writes, no spend.
- ·postgres
- ·seeding
- ·validation
- ·ci
- 9 min
When faker.js is exactly the wrong answer
faker.js generates 10,000 plausible names. It does not generate 10,000 names whose foreign keys resolve. The gap between fake values and seed data.
- ·tooling
- ·faker
- ·postgres
- ·seeding
- ·philosophy
- 11 min
Check constraints that lie
Postgres CHECK constraints often encode wishes. Where they leak (NULL, non-immutable expressions, NOT VALID, domains) and what to write instead.
- ·postgres
- ·constraints
- ·schema
- ·seeding
- 14 min
Inside the e-commerce profile: SKUs, carts, and the long tail of returns
Catalog distributions, basket sizes, return rates and seasonality in the satus e-commerce profile, and why it has no fashion-vs-electronics switch.
- ·profile
- ·ecommerce
- ·distributions
- ·postgres
- ·seeding
- 12 min
Three timezone bugs we found by seeding production-shaped data
Uniformly random timestamps hide timezone bugs. Business-hours timestamps surface them. Three bugs from support, and the catalog signals that predict each.
- ·postgres
- ·timezones
- ·testing
- ·seeding
- 9 min
JSONB columns that are secretly relational
Half the JSONB columns we see are key/value bags. The other half are arrays of IDs pointing at real rows, with no constraint. How to tell them apart.
- ·postgres
- ·jsonb
- ·modeling
- ·seeding
- 7 min
v0.2.0: deferred constraints, faster planning, and a smaller binary
Cyclic foreign keys now seed end to end via deferred constraints. Introspection drops from five round trips to one. The npm tarball is 77.6% smaller.
- ·postgres
- ·satus
- ·release
- ·foreign-keys
- ·performance
- 8 min
The CITEXT trap in Postgres unique indexes
A seed job asked for 10,000 users and inserted 6,200: a CITEXT unique index folded Alice and alice into one row. What CITEXT does and what satus generates.
- ·postgres
- ·citext
- ·unique
- ·collations
- ·seeding
- 8 min
Partitioned tables meet RLS, and nobody wins
RLS policies on a partitioned parent do not protect the children. What Postgres actually does, and the two-line workaround satus now prints.
- ·postgres
- ·rls
- ·partitioning
- ·seeding
- 11 min
Inside the medical-booking profile: why appointments are harder than they seem
Appointments cluster mid-morning and afternoon, almost never on holidays, with a long tail of no-shows. What the satus medical-booking profile encodes, and why.
- ·profile
- ·medical
- ·distributions
- ·postgres
- ·seeding
- 7 min
NULL vs NOT NULL is not the question
A support ticket about a nullable column that broke an app. The real question is what NULL means to your code, and Postgres gives you three answers, not two.
- ·postgres
- ·null
- ·semantics
- ·seeding
- 2 min
Introducing the satus log
A plain-text changelog and field notebook for schema-aware seed data, written for engineers who read RFCs for fun.
- ·meta
- ·postgres
- 6 min
Cyclic foreign keys in the wild
Most seed-data tools pretend cycles don't exist. They do. Here is how satus splits the graph, inserts with NULLs, and back-patches in a second pass.
- ·postgres
- ·foreign-keys
- ·graphs
- ·seeding
RSS, no email required.
We do not run a newsletter. The full feed lives at /blog/rss.xml. Add it to any reader. There are no tracking pixels in the feed and no cookies on this site.