railiance-platform/docs/s3-consumer-interfaces.md
codex cb321deeab
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Finish RPF-WP-0019 apps-pg controls and recovery
2026-08-20 22:58:45 +02:00

6.6 KiB

S3 consumer service interfaces

Work record: RAILIANCE-WP-0016 item 17; RPF-WP-0018 T04
Date: 2026-08-15, revised 2026-08-17
Contract version of this index: 1.1.0

Consumers bind to these contracts, not to Helm chart names or pod topology. Changing an engine behind a versioned interface does not bump the interface unless the consumer-visible fields change.

Interface Version Who it is for Authority
Shared application database apps-pg.v1 S5 apps that need an isolated database on apps-pg docs/apps-pg.md
Isolated platform database rapp-postgres.v1 Platform services that need a CNPG consumer on platform-pg rapp-postgres/declarations/rapp.yaml consumer_contract
Standing runtime secret ccr-workload-kv.v1 Workloads that need a KV path via External Secrets schemas/credential-change-request.schema.yaml
Short-lived lease credential-grant.v1 Operators/agents and dynamic DB roles credential-grants/catalog.yaml
Rapp credential bind rapp-lane.v1 How a rapp names the two lanes above docs/rapp-credential-lane-binding.md
Consumption-mode gate consumption-mode.v1 New orders for a restricted financial entity docs/consumption-mode-enforcement.md

Compatibility rules

  • A vN document may add optional fields. Removing or renaming a required field is vN+1.
  • Values never appear in an interface document. Paths, grant ids, CCR ids, and role names are the contract.
  • make pg-deploy / Bitnami DSN postgresql-ha-pgpool.platform.svc.cluster.local is not an interface. That stack is retired.

Quota disclosure

Added in 1.1.0 — additive, so no consumer contract breaks.

Tenancy Posture §10.2: quotas are disclosed, not discovered. Every consumer is told at provisioning what the platform will refuse to do for it, and told again when that changes. A consumer learning its statement timeout by hitting it in production is a disclosure failure, not a consumer bug.

The obligation this places on S3 is a standing one: a change to any value in the tables below is announced to bound consumers before it takes effect. The values themselves are read from the cluster CR and are the package owner's to set — this index publishes them, it does not choose them.

Retention disclosure carries the additional §7 rule from docs/placement-policy.md: on a shared cluster the effective erasure horizon is the maximum declared across co-residents, not the value the consumer requested. That number is disclosed, and it moves when a co-resident changes.

apps-pg.v1

Consumer supplies: app name, namespace, database name, role name. Platform provisions the role and CNPG Database, labels the namespace railiance.io/postgres-client=apps-pg, and publishes a runtime Secret. RW endpoint: apps-pg-rw.databases.svc.cluster.local:5432. Bootstrap role apps_admin is not a consumer credential.

Quotas and limits — declared in helm/apps-pg-cluster.yaml and helm/apps-pg-consumer-controls.sql, 2026-08-18. These values are published before the corresponding live rollout:

Property Value Note
max_connections 100 Explicit aggregate cap. Forty connections remain outside the declared three-consumer ceiling for operator/CNPG overhead.
Per-consumer connections 20 CNPG managed.roles[].connectionLimit, for both current roles.
statement_timeout 15s Per role; idempotent operator SQL because CNPG 1.28 has no managed-role settings field.
idle_in_transaction_session_timeout 15s Per role, same enforcement path.
Database boundary own database only CONNECT and TEMPORARY are revoked from PUBLIC; each consumer role receives them only on its own database.
CPU / memory 100m / 256Mi requests; 1 CPU / 1Gi limits Burstable QoS; memory is expected to bind before connections if workload size grows.
Instances 1 No HA. Restart recovery only, per the single-node rail.
Storage 10Gi
Backup 30d; daily 02:15 UTC + continuous WAL S3 prefix s3://railiance-platform-pg-backup/platform-pg/apps-pg/; backup and restore proof captured 2026-08-20.
Effective erasure horizon 30d, or the max across co-residents Shared-cluster rule from placement policy §7.
Declared ceiling / overflow 3 consumers / apps-pg-2 Memory is the binding safety constraint; provision the named overflow substrate before admitting a fourth.

The configuration and evidence gaps closed on 2026-08-20: LastBackupSucceeded=True, a 56-second scratch restore, and a 14/14 live boundary/noisy-neighbour run. Source configuration is not substituted for those artifacts; see docs/evidence/RPF-WP-0019-*.md.

rapp-postgres.v1

Consumer is a consumers[].declaration. Boundary unit is database-per-consumer. Credential type is openbao-dynamic-database-credential via grant rapp-postgres/<consumer>-<role>. Tenant identifiers are opaque.

Quotas and limits — authority is rapp-postgres's helm/platform-pg-cluster.yaml; reproduced here for disclosure, 2026-08-17:

Property Value Note
max_connections 100 Aggregate, not per consumer. ~14 per consumer (12 runtime + 2 migration) puts the practical ceiling near 6.
Memory limit 1Gi Expected to bind before connections do — ~10MB per backend. Memory pressure OOM-kills; connection exhaustion errors cleanly.
CPU 100m request / 1 limit
Instances 1 No HA.
Storage 20Gi
Backup retention 30d Instance-wide, per rapp-postgres ADR-0002.
Effective erasure horizon 30d, or the max across co-residents A consumer needing shorter cannot have it at P1. See docs/placement-policy.md §7.
Statement timeout consumer-set tenant-engine sets 5s for its own path; not a platform default.
Declared ceiling / overflow target 4 declarations / platform-pg-2 The isolation probe counts. rapp-postgres rejects a fifth declaration on one cell; ADR-0004 owns the number.

Service classes currently co-resident on platform-pg: latency-critical (tenant-engine) and batch (audit-core). Nothing prioritises between them — community PostgreSQL has no resource governor. Reported per Tenancy Posture §8.3.3.

ccr-workload-kv.v1 and credential-grant.v1

Unchanged semantics from docs/credential-change-approval.md and docs/credential-broker.md. The version name exists so a rapp can cite the lane without restating TTL, delivery, or revocation rules.

Not yet an interface

Valkey and in-cluster MinIO have capability blocks in SCOPE.md and no live service. They do not receive a v1 until a consumer exists.