feat: expose repository navigation queries
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / pytest-smoke (push) Failing after 2s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0230c-b06c-7641-808a-e191b6d1da49
This commit is contained in:
tegwick 2026-08-22 00:40:42 +02:00
parent 283bbf048e
commit e3e542f76c
9 changed files with 446 additions and 3 deletions

View file

@ -33,17 +33,39 @@ the API does not auto-create tables.
| `port.events.progress` | `POST /ports/events/progress` | Accepts only cataloged progress-family events |
| `port.events.interaction` | `POST /ports/events/interaction` | Accepts only cataloged interaction-family events |
| `port.projection.query` | `GET /ports/projections/{id}` | Rebuildable registry/message/event projections with provenance |
| `port.projection.query` | `GET /ports/projections/repository-navigation/repositories` | Snapshot-bound cross-repository classification navigation |
Available projection ids are `hub_registry`, `messages`, `progress_events`, and
`interaction_events`. The two event families use distinct stores and cannot be
submitted through each other's endpoint.
Repository navigation consumes an injected `RepoProjectionClient` implementing
the `port.repo` page reader. When supplied to `create_app`, the client is
refreshed at startup; a host scheduler can call the same idempotent
`RepositoryNavigationService.refresh()` for later full or incremental
generations. The client owns transport and credential routing—host paths and
credentials never enter projection payloads. Migration
`0003_repository_navigation` stores active state, normalized repositories, and
derived facets atomically.
The repository query accepts repeated primary/secondary domain, category,
capability-tag, business-stake, and business-mechanic filters. Values within a
family are ORed and families are ANDed. Opaque cursors are bound to the active
content hash and normalized filters; a rebuild or changed filter returns 409.
Every response includes source snapshot/revision, checked/rebuilt times, and a
canonical content hash. MCP exposes the same surface through
`query_repository_navigation` and `get_repository_navigation_facet`. No
classification-write endpoint exists.
## Backend boundary and readiness
The app is created with an injected `PortStore`. `InMemoryPortStore` remains
available for deterministic tests and local contract smokes. Production uses
`PostgresPortStore`, whose registration, messaging, progress, interaction,
compatibility, import-lineage, and audit records are transactionally durable.
Repository navigation readiness is `ok`, `stale`, `unavailable`, or
`not_applicable` depending on whether a `port.repo` client is configured and a
valid generation has been accepted.
`GET /healthz` proves the process is alive. `GET /readyz` fails with HTTP 503
when the active backend does not match `HUB_CORE_BACKEND`, or when the memory