§00|The log

field notes from the satus team.


  1. 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
    4 min
  2. 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
  3. 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
    5 min
  4. 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
  5. 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
    7 min
  6. 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
    6 min
  7. 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
    5 min
  8. 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
    6 min
  9. 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
    5 min
  10. 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
    4 min
  11. 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
    9 min
  12. 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
    2 min
  13. 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
    4 min
  14. 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
    5 min
  15. 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
    6 min
  16. 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
    2 min
  17. 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
  18. 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
    7 min
  19. 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
    6 min
  20. 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
    5 min
  21. 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
    8 min
  22. 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
    7 min
  23. 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
    12 min
  24. 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
    4 min
  25. 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
    6 min
  26. 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
    10 min
  27. 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
    12 min
  28. 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
    7 min
  29. 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
    5 min
  30. 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
    8 min
  31. 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
    15 min
  32. 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
    10 min
  33. 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
    7 min
  34. 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
    9 min
  35. 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
    5 min
  36. 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
    4 min
  37. 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
    9 min
  38. 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
    11 min
  39. 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
    14 min
  40. 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
    12 min
  41. 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
    9 min
  42. 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
    7 min
  43. 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
  44. 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
    8 min
  45. 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
    11 min
  46. 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
    7 min
  47. 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
    2 min
  48. 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
    6 min
§01|Subscribe

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.