Platform retention classes
Verified against production source commit 6cdb6c78b845d40ae7d960d36ea984fd5a972639. The final source census has 41 active Platform tables: 38 authoritative records, one derived catalog and two operational outboxes. Twelve unused tables are retired forward.
First-pass source: f9df58bc433b568e2edfcc16da243c54afc22b2a (four records).
RFC-3 first makes the four previously labelled authoritative records effective, before reviewing the remaining Platform tables. Migration 099_v2_platform_authoritative_retention_classes.sql adds distinct disposal statements without changing records or introducing a deletion schedule. The 099 category remains Startup; its v2 filename follows the existing 099_v1 resources.
| Record | Authority and disposal boundary |
|---|---|
environment_state | The declared opaque document and monotonic version belong to Platform’s custody service. Replacement advances the existing version; consumer interpretation of expiry does not delete this record. The state update and catalog announcement share a transaction. |
backup_policy | The operator declares cadence, artifact retention and storage thresholds. Disabling the schedule retains that declaration. Backup-file retention does not govern deletion of the policy row. |
backup_runs | The store preserves reports of both success and failure. ON CONFLICT (run_id) DO NOTHING prevents a repeat report from changing the historical recovery point. Artifact pruning does not remove these reports. |
backup_alerts | The record is an announcement claim keyed by scope, kind and condition. It prevents repeated claims across restarts. Claim-before-publish can lose a notification on publication failure, so the claim alone is not proof of Notify delivery. |
The proof inventory binds each class to its creating identity, migration owner, running startup registration and separate disposal statement. The class review is source evidence; it does not assert that a migration has been applied to a live estate.
Re-verify with the five commands in the retention guide. The adjacent executable checks are PlatformMigrationOwnershipIntegrationTests, EnvironmentStateStoreIntegrationTests, BackupScheduleCheckIntegrationTests and BackupAlertIntegrationTests in StellaOps.Platform.WebService.Tests. The alert tests use isolated PostgreSQL and Valkey fixtures, not the estate’s notification queue.
The backup alert detail contains the fields used to build its complete condition key and scope. The primary key therefore limits identical detail to one stored condition under the actual poller contract. This does not limit the number of distinct historical conditions. Backup run detail has a different contract: the reporting script repeats producer/readability metadata across distinct run IDs. Run uniqueness does not establish a one-copy payload bound; that declaration remains under review without deleting or rewriting reports.
Remaining record classes
Migration 099_v8_platform_shared_tenants_retention_class.sql classifies Platform’s shared.tenants source-of-truth. SharedTenantsCatalogProjection inserts each tenant once from Authority’s catalog and never re-keys it, because the row id is the foreign-key parent of Platform’s tenant-scoped records. A catalog tombstone suspends the row. Release Orchestrator also creates the table in its own database. That copy is the registered X-new-1 exception, so under the owner ruling of 2026-09-24 Platform alone states the class.
Migration 099_v7_platform_environment_settings_retention_class.sql classifies environment_settings source-of-truth. It is the installation-scoped key/value layer of the settings composer. PostgresEnvironmentSettingsStore upserts by key, and a row leaves only through the store’s explicit delete of that key. The census omitted this table until the P13 chain fold read 064’s rename of its staging copy back into the name.
The protected Retention:Authority:LoginAttempts row is one authoritative installation policy, changed only through its typed version/reason boundary. Generic writes and deletion are refused. Each change atomically appends the old/new pair and verified actor to Platform’s P6 delivery outbox; Timeline owns the acknowledged audit history. The stream-specific published requirement preserves pending changes across age limits and restore epochs without changing unrelated stream rules. See the policy contract.
Migration 099_v6_release_topology_projection_retention_classes.sql classifies the nine release.topology_* projection tables derived-rebuildable: TopologyInventorySynchronizer reads ReleaseOrchestrator’s source topology through its API and replaces each tenant’s slice every pass.
Migration 099_v5_platform_retention_classes.sql classifies 34 further authoritative tables: assistant content and user choices; connector credentials; context, translation and user preferences; cryptographic provider/trust configuration; current setup drafts and encrypted inputs; federation facts, signed bundles, consent commitments, received observations and replay receipts; privacy-budget accounting; control-bundle definitions, versions and submitted materialization intent; and canonical actor identity/erasure state.
These are retained inputs, artifacts or decisions. In particular:
- Setup state is upserted under the installation scope, not appended as a queue history. Creation and restart lock/read the retained state in one owner-database transaction, preserve freshly committed drafts, move the exact protected secret bytes and replace the session together. Retained inputs under an ambiguous replacement ID stop the operation without merging or deleting them. Finalization deletes the session’s secret inputs.
- The federation peer inbox rejects reuse of a source-site/bundle identity with a different digest. Removing old sender delivery state must not remove that receiver replay guard.
- Privacy-budget periods record spent epsilon; expiring the accounting row could reset a spent budget. Signed, randomized bundle output is retained as an artifact rather than described as reproducible from current inputs.
- Materialization rows currently record queued operator intent and expose its history. This classification does not claim that a materialization executor is wired. Bundle/version foreign keys govern their custody.
- Actor erasure and explicit configuration updates retain their existing owner-specific behavior; this review introduces no age-based deletion for those records.
The federation installation record stores only site identity, policy-version label and times. Its singleton constraint permits one row; the owner store rejects a different site while allowing policy-version updates. The peer inbox stores receipt/source/bundle identifiers, the accepted envelope digest and receipt time. The verified receiver compares a duplicate’s digest before accepting it, and updates aggregate state in the same transaction as the first receipt. FederationPersistenceIntegrationTests verifies both restart continuity and changed-digest refusal. These scalar records have completed identity/exemption review; federation signed artifacts, observations, consent-set audit and received aggregates retain their separate open declaration obligations.
Setup writes reject stale state, and secret writes validate the current session while holding the same installation-row lock. A concurrency refusal asks the caller to refresh or resume the current state. A setup step may already have completed an outward action before its final state write encounters a conflict; this repair adds neither an automatic retry of that action nor an idempotency guarantee for it. The persistence revision stays internal and is absent from the JSON/API contract. PlatformSetupAtomicStoreTests exercises concurrent initial creation, restart and secret writes, stale updates, exact-byte rollback and replacement-ID refusal against PostgreSQL. The in-process test backend shares one paired state. An equivalent replay keeps the retained row and its observation timestamps unchanged. This comparison uses persisted field values and JSON structure, including reordered draft keys; the stale-revision check runs first, so matching content cannot excuse a stale write.
Release-control bundles keep operator catalog identities scoped by tenant and slug. Each publication keeps its own version record and component rows; repeating the component metadata does not collapse separate publications. A nonempty materialization idempotency key is scoped to tenant, bundle and version. Its queued record describes a submitted intent, not completed materialization. Version and component writes share one transaction, so invalid component JSON does not leave a partial publication. The catalog, publication and intent records contain scalar operator metadata; component JSON retains its separate open repetition obligation.
Actor identity keeps mutable principal attributes under the tenant/actor-reference key. The current authenticated self-upsert validates a UUID subject and retains that UUID as the external subject used by the Authority subject-access join. Erasure keeps a positive marker and refuses rehydration; it deliberately retains the external-subject field. The broader store and historical fixture accept other external-subject text, so this review does not claim universal erasure of that field or change its custody policy. The minimized catalog update shares the owner transaction; separate audit emission follows that commit.
Translation overrides are operator message records keyed by tenant, locale and message key. Reads combine the shipped baseline, current system overrides and the selected tenant’s overrides in that order. Tenant writes never change the shared registry. System writes and deletes refresh this host’s shared messages, including callers in shared libraries; deletion restores the lower-precedence message or removes a system-only key/locale. Failed or cancelled refreshes keep the previous complete snapshot and surface the failure. The owner write and local refresh are not one database transaction, and this adds no distributed invalidation. Existing header selection and authorization are unchanged; their broader qualification is separate from this message-identity and cache-custody repair.
The trust administration store retains three scalar record kinds. Issuers have an opaque ID and a tenant-scoped, case-insensitive URI coordinate. Certificate registrations have an opaque ID, a tenant-scoped serial coordinate and optional key/issuer references checked in the same tenant. Blocking or revocation retains those records and changes their declared status. Transparency configuration replaces one current row per tenant; invalid URI input leaves the retained row unchanged. These records contain labels, references, validity times and requested configuration, not certificate bytes or inclusion proofs. The inventory reader’s static/demo health fields do not prove issuance, key rotation, verification or transparency enforcement. AdministrationTrustRecordIdentityTests exercises the actual PostgreSQL store. The separate trust_keys.metadata_json payload can repeat across records and remains under review; scalar identity does not supply its repetition or admission bound.
doctor_capabilities is a derived catalog. DoctorCapabilityStore.RegisterAsync reconstructs a service’s claimed check set and deletes absent checks for that service in the same transaction. The catalog stores declarations, not check results or proof that a remote service is healthy.
Completed transport retention
The PostgreSQL-backed Platform host runs PlatformRetentionService after its startup migration registration. It calls platform.prune_completed_outboxes() on startup and daily thereafter.
| Table | Eligible records and preserved authority |
|---|---|
operator_provider_change_outbox | Only completed records with a completion timestamp and no lease. Authority retains the append-only provider-retirement receipt; Platform preferences remain independently authoritative. |
telemetry_federation_outbox | Only delivered records with a delivery timestamp and no claim. Signed bundles, peer receipts, consent commitments and privacy-budget records remain intact. Failed delivery records are preserved for repair. |
On each successful pass, eligible rows older than 90 days or beyond the newest 10,000 per scope are reclaimed. The scope is the tenant for provider changes and the destination site for federation delivery. Selection is rechecked against the current scope and completion timestamp, so an update while pruning waits preserves the renewed record for a later pass.
Configuration:
Platform:
Retention:
RetentionDays: 90
TerminalRowsPerScope: 10000
Interval: "1.00:00:00"
All values must be positive; the SQL function also rejects null/nonpositive days or row budgets. These are transport-state defaults, not retention rules for credentials, signed artifacts or privacy accounting. Failures are logged and retried without changing the eligibility predicate.
The existing service Doctor surface includes doctor.platform.retention.outbox-budgets. It reports relation bytes, total and maximum per-scope row counts, expired eligible rows, and held terminal rows. The row figure also acts as a warning threshold for the entire scope backlog; active or leased work is never deleted to satisfy it. Evidence contains aggregate numbers and scope kinds, not tenant/site identities, credentials or payloads.
PlatformRetentionIntegrationTests runs against a non-superuser database owner. It checks terminal/active/lease safety, separate-scope budgets, independent-record preservation, idempotence, invalid limits, the running keeper and completion changes during a blocked prune.
Unused schema retirement
099_v3_retire_unused_platform_tables.sql retires 12 unused, empty tables: Platform’s completed identity-provider import source, the three integration-health/watermark projections, the three release/activity/approval projections, and five earlier run-detail projections. Repository-wide caller inspection and a read-only database count found no active storage callers and zero rows. Authority’s current provider store, control bundles and trust records remain separately owned.
The migration locks and checks every candidate before dropping anything. Unexpected records stop convergence with SQLSTATE 55000 for explicit preservation/review. Drop order handles the gate-ledger-to-input-snapshot foreign key; no cascading drop conceals an additional dependency. Release Orchestrator’s foreign-table guard keeps the historical names, so reintroducing either retired or current Platform tables into its database remains detectable.
Owner capacity monitoring (DIP-17)
The PostgreSQL Platform host adds a leased probe on its explicit owner pool. Migration 099_v10_capacity_probe_receipt.sql creates platform.capacity_probe_receipt; inserts retain the latest 90 receipts and never remove the newest. doctor.platform.capacity.budget measures the 25 registered entries, including Platform’s topology inventory, and rejects absent required measurements, missing/stale receipts and stop-line breaches. Release Orchestrator’s source tables are not measured through Platform’s connection.
The capacity guide records the initial envelope, dated measurement and event-rate basis. This monitoring does not complete all 49 Platform identity declarations or intercept writers. A pause flag is a required action, not proof of admission enforcement. Existing settings, provider-change and credential custody remain separate. PlatformProductionHostStartupMigrationTests exercises the actual fresh/restart/upgrade host and its probe; run it with the targeted wrapper and -BuildProjectReferences.
Assistant tip identity
An authored tip is identified by tenant, route pattern, optional context trigger, locale and sort order. 099_v11_assistant_tip_null_identity.sql keeps the existing constraint name and makes null context triggers compare equally. Repeating a page-tip update therefore retains its tip ID and returns the replacement content through the existing store and read path. Context tips and distinct tenant, route, locale or sort-order identities remain separate.
The forward migration requires PostgreSQL 15 or later. It checks the owned constraint and locks the table while checking and replacing it. Existing ambiguous identities, including inactive tips, stop migration with SQLSTATE 55000; every authored record and the old constraint remain intact. It never chooses or deletes a winner. A replay retains the completed constraint. The historical 060_StellaAssistant.sql is unchanged.
AssistantTipIdentityMigrationTests exercises fresh and populated upgrades, replay, concurrent updates, distinct scopes and ambiguity preservation on PostgreSQL 16 and 18.1. The production-host migration test verifies the same store behavior across startup and restart. This repair does not establish payload limits or writer admission for Assistant records; those remain separate review obligations. Assistant routes take the tenant from the authenticated principal; see Stella Assistant.
