feat: add guarded State Hub inbox read projection pilot
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a06ed7-828d-7ca0-a8d4-0c3e5a0c4102
This commit is contained in:
parent
9724b273a1
commit
6fb5ce285c
6 changed files with 343 additions and 0 deletions
67
docs/statehub-inbox-read-pilot.md
Normal file
67
docs/statehub-inbox-read-pilot.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# 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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue