# State Hub inbox read pilot `GET /ports/projections/statehub-inbox` is an opt-in, authenticated read-only projection over the existing `agent_messages` model. It is distinct from `/ports/messaging/messages`, which accepts new message envelopes and does not implement State Hub's read/archive lifecycle. Enable only after validating and importing a consistent source snapshot: `HUB_CORE_STATEHUB_INBOX_READS=1`, `HUB_CORE_STATEHUB_INBOX_AGENT=state-hub`. PostgreSQL and the configured operator bearer token are required. Disabled by default. No POST/PATCH/DELETE exists on the pilot endpoint. Imported history never emits messages or notifications. The response is the State Hub `MessageRead` list shape. Parameters are `to_agent` (must match the configured pilot agent), exact `from_agent`, `unread_only` and `limit` (1–1000, default 50). Broadcast messages are included; archived messages are excluded. Results order by created_at descending, then ID for ties. Query transactions are read-only. Responses carry `Cache-Control: no-store` and `X-Hub-Core-Read-Mode: snapshot-pilot`. This proves one literal agent inbox. It does not claim repository rename/alias resolution, unscoped fleet reads, thread lookup, continuous freshness, or writer cutover. The importer preserves thread roots so later history work need not reconstruct dangling identities. ## Snapshot and import Capture messages with one source PostgreSQL read-only, repeatable-read transaction. Preserve id, sender, recipient, subject, body, thread_id, read_at, archived_at and created_at, including archived/thread-root records. Keep the raw snapshot in private temporary storage; commit only hashes and counts. The bundle has schema `hub-core.statehub-inbox-snapshot.v1`, `source`, `captured_at`, `messages`, `count`, and `content_hash`. Use `snapshot_hash` from `hub_core.runtime.inbox_projection` for canonical UTC/UUID normalization. `import_snapshot(session, bundle, expected_hash=..., apply=False)` validates; `apply=True` imports under a caller-owned transaction. The caller must commit only on success and roll back any exception. PostgreSQL apply locks the target message table before inspecting it. Different existing content refuses all changes; exact repeats are no-ops. Thread roots insert before replies. Duplicate IDs, malformed rows, hash/count mismatch, absent provenance, missing roots and cycles are rejected. Use the existing workload database credential delivery inside the receiving pod; never export database credentials into evidence. No schema migration or new secret is required. This is a one-time migration helper, not a message sending API or an automated synchronization loop. ## Pilot sequence and rollback 1. Keep State Hub as sole message writer; capture source revision, instance, repeatable-read snapshot, data hash and expected filtered inbox results. 2. Import only into an empty receiver, verify all row hashes/counts and replay as a no-op. Deploy the disabled reader image, then enable the private pilot. 3. Compare the same frozen source rows with authenticated receiver responses: all/unread/sender/limit cases, broadcast inclusion and archive exclusion. Check unauthenticated rejection and absence of writes. A later live State Hub read is a freshness observation, not the original snapshot oracle. 4. Disable the reader flag and verify the endpoint returns 404; re-enable and recheck the same hash. Retain the imported rows for review; do not delete history as a rollback technique. Runtime rollback uses the previous image. Transport from State Hub must be explicitly admitted by rapp-core-hub's NetworkPolicy. Scope any pilot exception to State Hub API pod labels and the candidate port. No public Ingress or production message-writer change is part of this pilot. The operator bearer stays in its existing credential lane; production caller credentials and ongoing freshness require their own cutover.