Engineering / PostgreSQL benchmark study

Reliable evidence.
Measured honestly.

Inside Gentlity: Benchmarking Reliable AI Agent Evidence Ingestion with PostgreSQL

Before asking how fast evidence can arrive, we asked whether we could account for every event. A look inside our first PostgreSQL-backed ingestion baseline.

Bounded local benchmarkExperiments: 16 October 2026
A LOCAL OBSERVATIONPOSTGRESQL 17.11
5.00 events / s
EVENT → ACK → RECEIPT1,200 / 1,200Persistence and canonical bindings checked
4 synthetic tenantsNo capacity extrapolation

An agent can finish its task while the evidence of that task fails to arrive. A timed-out request might already have committed. A replay might duplicate a fact. A valid credential might be used against the wrong tenant. Before an ingestion rate is useful, those distinctions need to survive the entire path to storage.

For Gentlity, that makes correctness part of the benchmark, not a preface to it. We started with a small control run, then measured one deliberately modest workload: four synthetic tenants, five events per second, and a local PostgreSQL database. Here is what we observed, how we checked it, and where the evidence stops.

5.00events / second900 committed ACKs · 180 seconds
19.23ms HTTP p95Transport time, not database-only
26.43ms HTTP p99900 measurement-window requests
0errors / timeouts / retriesAcross all 1,200 HTTP attempts
1,200events verified persistedWarm-up + measurement; no cooldown arrivals

What an ingestion acknowledgement means

Gentlity connects agent evidence to reliability measurement and operational decisions. The ingestion path accepts run lifecycle events, evaluation outcomes and measurement-health observations. A receipt gives the platform a stable identity for a delivered event; a canonical digest lets it distinguish the same content arriving again from different content using the same identity.

In the tested integration, a machine credential establishes tenant authority. The application validates the request and registered deployment identity, builds the canonical digest, and persists the receipt and typed evidence in a PostgreSQL transaction. A new committed event receives HTTP 201; an identical committed replay receives HTTP 200. This is an application contract backed by database checks, not a claim that any HTTP success alone proves correctness.

The tested logical pathFrom an agent event to a committed receipt.
  1. 01SDK + raw HTTP

    Native v2 agent runs and a v1 compatibility workload.

  2. 02Authenticated API

    Machine credential establishes tenant authority; request schema is validated.

  3. 03Canonical evidence

    Source admission and deployment binding; canonical digest and identity checks.

  4. 04PostgreSQL commit

    Receipt and typed evidence in the canonical transaction; ACK follows commit.

A separate verification process reads the committed receipt and checks digest, organization and deployment. This additional work is included in database observations. Logical flow only: no production deployment topology, queue or replica is implied.

The benchmark adds its own independent read after each acknowledgement. It checks the stored receipt, canonical digest, organization, deployment and acknowledged run identity. That check improves our ability to detect a broken experiment, but it also adds database work. We keep that overhead visible throughout the results. See evidence note 3.

The experiment we actually ran

We ran two separate experiments. Evidence ingestion correctness validation asked whether the system preserved each fact and handled repeated or conflicting requests safely. The PostgreSQL ingestion performance baseline measured one selected workload. The experiments used different PostgreSQL versions; they were not a version comparison, and neither searched for saturation.

DetailCorrectness validationPerformance baseline
PostgreSQL16.1517.11
Hardware / OSLocal Mac; not a version comparisonApple M5 Pro, 24 GiB RAM, 15 logical CPUs; macOS 26.5.1 arm64
Workload12 synthetic events and three controlsFour synthetic tenants; 1,080 SDK-v2 events and 120 raw-v1 lifecycle records
TimingSmall correctness check60s warm-up, 180s measurement, 60s cooldown
DeliveryReal authenticated local HTTPReal authenticated local HTTP through a benchmark-owned SDK transport bridge
Planned rateBounded low-load control5 unique events/s; maximum 6 HTTP attempts/s
Request concurrencyMaximum 2 configuredMaximum 16 configured; highest observed HTTP inflight was 1
Persistence checksReceipts, digests, replay and tenant/conflict controlsEach ACK checked against PostgreSQL; final exact receipt-set and digest/binding reconciliation

The performance baseline ran on an Apple M5 Pro Mac with 24 GiB RAM and 15 logical CPUs, macOS 26.5.1 on arm64, and Python 3.11.17. PostgreSQL was a dedicated native local cluster; the API and database used loopback networking. The machine also had development activity, so this was not a dedicated-host capacity test. No customer data, cloud service or paid model calls were involved.

The SDK portion preserved whole four-event runs: start, a passing evaluation, completion and a healthy measurement report. The raw-v1 portion supplied compatibility lifecycle records. Actual encoded payloads were 371–619 bytes, below the planning reference near 2 KiB; the plan permitted smaller valid payloads. Those sizes matter when comparing any later experiment.

Safety limits included a 1,200-event cap, 1,440-attempt cap, three attempts per identity, 2 GiB scratch ceiling and combined sampled RSS strictly below 6 GiB, together with disk, CPU, connection and memory-pressure guards. The test had a 15-minute deadline and automatic cleanup of its isolated database. These were sampled soft limits, not native OS resource quotas. See evidence note 2.

Evidence ingestion correctness validation

The successful correctness validation acknowledged and verified persistence for 12 events in 15 HTTP attempts on PostgreSQL 16.15. Canonical digests matched. The three additional requests tested replay, tenant isolation and conflicting content.

Correctness validation · PostgreSQL 16.15Three controls. One unchanged receipt set.
Identical replay
HTTP 200Duplicate ACK, existing fact
Foreign tenant credential
HTTP 404Tenant-hidden response
Changed-content identity
HTTP 409Conflict, original digest preserved
Sanitized rendering of the recorded correctness validation results. Receipt count remained 12 after all controls. These controls were separate from the performance run. Evidence notes ↗

Evidence Integrity and Tenant Isolation

Beyond measuring ingestion performance, we validated several important reliability guarantees. Duplicate submissions were handled without creating additional records, cross-tenant access was correctly restricted, and conflicting evidence submissions were rejected without altering previously stored data.

All 12 test events remained consistent throughout these checks, confirming the expected behavior of evidence persistence, isolation, and integrity controls under the tested conditions.

Sampled scratch and total RSS peaks for the successful correctness run were 51.17 MiB and 259.23 MiB respectively. These are sampled observations, not guarantees about instantaneous resource peaks. They also belong to the correctness run, not the PostgreSQL 17.11 performance result. See evidence note 1.

PostgreSQL ingestion performance baseline

The 180-second measurement window offered 900 events and received 900 committed acknowledgements: 5.00 events per second. Every one of those event identities was included in the final persistence verification. Across the full experiment, including warm-up, 1,200 events were acknowledged and verified. Cooldown introduced no new arrivals or attempts.

Acknowledged throughput

A steady offered rate. A deliberate stop.

Committed ACK completions per second · 10-second bins

Acknowledged throughput over the benchmark timelineTen-second bins alternate between 5.1 and 4.9 events per second during 60 seconds warm-up and 180 seconds measurement, then zero for 60 seconds cooldown. Measurement average is 5.00 events per second.02460s60s120s180s240s300sCooldown
60sWarm-up
180sMeasurement · 900 ACKs
60sCooldown · no arrivals
Visualization of measured data, not an inferred capacity curve. Each bar uses the preserved ten-second completion count. The dashed line marks the configured 5 events/s target during arrivals. Evidence notes ↗

Configured rate describes the workload the generator intends to offer. Achieved throughput counts observed completions in a defined interval. Here they agreed over the measurement window. Ten-second completion bins alternated between 5.1 and 4.9 events/s, reflecting the preserved scheduling of whole SDK runs; that is not a changing capacity estimate.

Averaging across the intentionally idle cooldown would answer a different question. We report the 180-second measurement window separately rather than use the full controller duration as a throughput denominator.

Reading the latency distribution

For the 900 measurement-window requests, nearest-rank HTTP latency was 16.83 ms at p50, 19.23 ms at p95 and 26.43 ms at p99. The zero-based chart below shows those observed percentiles, not a prediction for larger loads.

HTTP transport latency

The measured distribution, in milliseconds.

Nearest-rank percentiles · Local PostgreSQL baseline · 900 requests

PostgreSQL ingestion HTTP latency percentilesZero-based bar chart: p50 16.83 milliseconds, p95 19.23, p99 26.43. HTTP time excludes persistence verification queries.0102030p5016.83p9519.23p9926.43ms
p50
16.83 ms
p95
19.23 ms
p99
26.43 ms
Visualization of measured data. Zero baseline. Source: recorded HTTP request measurements. HTTP RTT excludes SDK enqueue and the subsequent persistence verification query. Evidence notes ↗

This is client-observed HTTP transport time. It is not database-only query latency, transaction duration, authentication-stage time or SDK enqueue-to-acknowledgement time. The persistence verification query runs after the HTTP response and is excluded from this latency, while still contributing database and driver work during the experiment.

Across all 1,200 requests, the ledger recorded zero HTTP errors, timeouts or retries. That is the observed outcome of this run, not an error-rate guarantee or confidence bound for production. With observed HTTP concurrency of one, the experiment also says little about contention at the configured concurrency ceiling. See evidence note 2.

Close the accounting before interpreting the speed

A successful request log is only one part of the record. The benchmark compared the final receipt-ID set with its expected events, then checked every stored canonical digest and tenant/deployment binding before deleting the disposable cluster.

Recorded result excerptAccounting that closes.

Visualization of recorded results, with identifying details removed. Not a runtime screenshot.

{
  "workload": "Local PostgreSQL ingestion",
  "scope": "full run, including warm-up",
  "postgres": "17.11",
  "offered": 1200,
  "acknowledged": 1200,
  "persisted": 1200,
  "http_statuses": {
    "201": 1200
  },
  "errors": 0,
  "timeouts": 0,
  "retries": 0
}

Download the sanitized measurements (JSON) ↗

The checks found no missing or extra receipt and no digest or binding mismatch. The performance run verified the positive bindings of all four tenants; it did not repeat the correctness run's foreign-credential, replay or changed-content controls. We keep those results separate. Neither test performed a crash-recovery, restart or failover drill.

The retained evidence contains request ledgers and successful persistence checks, not a database dump or a fresh database inspection after cleanup. That is the scope of the persistence claim.

Resource observations are context, not headroom

The performance run's full-run sampled scratch maximum was 53.46 MiB, combined resident memory (RSS) maximum 277.05 MiB, and maximum sampled database connection count four. These include startup and warm-up activity. RSS sums can double-count shared PostgreSQL pages, and sampling can miss transient peaks.

Read the database counter details

Inside the measurement window, the first and last PostgreSQL samples spanned 178.574 seconds. Their WAL counter delta was 2,861,662 bytes and database-size delta was 1,444,700 bytes. Those endpoints do not cover exactly 180 seconds, and PostgreSQL counters may lag. We do not turn them into a per-event storage cost or a production cost model.

The same sampled window recorded 3,788 commits and 2,676 rollbacks. The rollback counter is not a failed-ingestion count: all HTTP requests returned 201 and all receipts verified. Monitoring and verification queries and session cleanup contribute transaction work; individual rollback causes were not attributed. Likewise, the sampled audit-row delta is not a final audit-table reconciliation.

No short lock waits were observed in the samples, but that does not prove contention was absent. Pool checkout delays, authentication-stage timing, application-only CPU, active-versus-idle connections, final typed-table counts and checkpoint attribution remain unmeasured. See evidence note 3.

What we learned, and what comes next

We strengthened our benchmark tooling with pre-submission contract validation to ensure test data conforms to the ingestion API before performance measurements begin. Offered, attempted, acknowledged and persisted events answer different questions, and all four need to reconcile.

The measured lesson is deliberately smaller: this selected local workload sustained five acknowledged events per second with the latency distribution shown above, while the final receipt checks held. We did not measure maximum PostgreSQL throughput, enterprise capacity, customer counts or a production SLO. We do not extrapolate this rate into a daily-volume promise.

Future work should quantify verification overhead, repeat matched workloads, and then investigate lock contention, retry/audit amplification, connection pressure, WAL growth and tenant-skewed historical queries in future test scenarios. Those workloads have not been measured in this study.

Reliability engineering benefits from a result whose boundaries are as clear as its headline. For this baseline, the useful artifact is a reproducible workload, a closed receipt ledger and a measured local observation—not an untested scalability claim.

Evidence notes

  1. Correctness validation. Derived from the preserved successful correctness validation result and execution report: PostgreSQL 16.15, 12 persisted events, 15 attempts, the three control responses and sampled resource maxima.
  2. Performance baseline. Based on the recorded HTTP request measurements. Quantiles were independently recalculated from the 900 requests sent during seconds 60–240; acknowledgement throughput uses response-completion times in that same window. The full-run count includes warm-up; cooldown adds no events. Experiment date: 16 October 2026, not a publication date.
  3. Implementation and resources. Checked against the integrated ingestion route, evidence service, verification process and raw resource samples. Commit precedes acknowledgement; verification queries add work. Architecture is a logical representation of the tested path, not a production topology. The measurement extract below includes the chart values without credentials or identifying tenant data.

The sanitized measurement extract provides the chart values without credentials or tenant IDs. To place this work in context, explore Gentlity's product, open-source SDK and our introduction to Agent Reliability Engineering.

Explore the engineering context

Evidence is the starting point.

Connect measurable agent behavior to reliability decisions.

Explore Gentlity