Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a053ff-1d6f-7fe2-ac1c-a6eb40a42a0c
146 lines
7 KiB
Markdown
146 lines
7 KiB
Markdown
# Hub Core runtime
|
|
|
|
The runtime implements the packaging decision in ADR-0001, the minimal
|
|
vertical in `HUB-WP-0004-T04`, and the durable Core Hub absorption boundary in
|
|
`HUB-WP-0005`. Public authority still moves only through the gated deployment
|
|
slices in the accepted absorption plan.
|
|
|
|
## Processes
|
|
|
|
The `runtime` dependency extra installs one `hub-core` command with three
|
|
process modes:
|
|
|
|
```bash
|
|
uv sync --extra runtime
|
|
hub-core api --host 127.0.0.1 --port 8010
|
|
hub-core mcp --host 127.0.0.1 --port 8011 --api-base http://127.0.0.1:8010
|
|
hub-core migrate head --database-url postgresql+asyncpg://...
|
|
hub-core migration validate core-hub-export.json
|
|
hub-core migration import core-hub-export.json --database-url postgresql+asyncpg://...
|
|
hub-core migration export --database-url postgresql+asyncpg://... --output reverse-delta.json
|
|
```
|
|
|
|
The migration command converts the async PostgreSQL URL for the packaged
|
|
synchronous Alembic environment. Production must run migrations explicitly;
|
|
the API does not auto-create tables.
|
|
|
|
## Runtime ports
|
|
|
|
| Port | Initial path | Behavior |
|
|
| --- | --- | --- |
|
|
| `port.registry` | `POST /ports/registry/registrations` | Validates and idempotently records a descriptor/manifest package |
|
|
| `port.messaging` | `GET/POST /ports/messaging/messages` | Addressed messages with optional conversation identity |
|
|
| `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 |
|
|
| `port.projection.query` | `GET /ports/projections/workloads` | Normalized authoritative workload projection and exact resolution |
|
|
|
|
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.
|
|
|
|
Production can configure the built-in HTTP adapter with
|
|
`HUB_CORE_REPO_MANAGER_BASE_URL`; optional
|
|
`HUB_CORE_REPO_MANAGER_API_TOKEN` bearer authentication and
|
|
`HUB_CORE_REPO_MANAGER_TIMEOUT_SECONDS` remain transport concerns. The runtime
|
|
refreshes at startup and every `HUB_CORE_REPO_PROJECTION_REFRESH_SECONDS`
|
|
(default 300). A failed scheduled refresh preserves the last generation as
|
|
stale; set the interval to `0` only when an external scheduler owns refresh.
|
|
|
|
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.
|
|
|
|
Workload projection uses a distinct injected `WorkloadProjectionClient` and
|
|
the authoritative `helixforge.workload-reference/v1` identity pair. Migration
|
|
`0004_workload_projection` stores only normalized transport rows and source
|
|
provenance. List and `/resolve` routes require explicit rapp/name/deployable
|
|
values and return unknown instead of consulting owners, repository names,
|
|
paths, or aliases. MCP exposes `query_workloads` and
|
|
`resolve_workload_reference` over those GET-only routes.
|
|
|
|
## 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
|
|
backend is used without explicit permission. Development and test permit it by
|
|
default; the OCI image sets production-safe defaults:
|
|
|
|
```text
|
|
HUB_CORE_ENV=production
|
|
HUB_CORE_BACKEND=memory
|
|
HUB_CORE_ALLOW_EPHEMERAL=0
|
|
```
|
|
|
|
Set `HUB_CORE_BACKEND=postgresql` and `HUB_CORE_DATABASE_URL` in production.
|
|
Readiness checks the database and continues to fail closed if the selected
|
|
backend is unavailable. A local image smoke may opt in to memory with
|
|
`HUB_CORE_ALLOW_EPHEMERAL=1`.
|
|
|
|
The compatibility adapter is enabled by coherent route groups in
|
|
`HUB_CORE_V2_GROUPS`; writes require the corresponding value in
|
|
`HUB_CORE_V2_WRITE_GROUPS`. Startup rejects overlap with
|
|
`CORE_HUB_V2_WRITE_GROUPS`. Supported groups are `system`, `registry`,
|
|
`credentials`, `interaction`, and `deferred`. Static operator authentication
|
|
uses `HUB_CORE_API_TOKEN`; imported consumer keys are verified by hash.
|
|
|
|
Migration bundles cover all seven Core Hub source tables. They preserve stable
|
|
IDs and timestamps, reject secret-shaped material and digest drift, record
|
|
counts/identity sets/canonical hashes, and return the original import-run ID
|
|
when the same bundle is replayed. Reverse export contains prefixes and hashes,
|
|
never raw keys.
|
|
|
|
## OCI image
|
|
|
|
The `Containerfile` uses `uv.lock` with `uv sync --frozen`, installs the runtime
|
|
extra, runs as UID/GID 10001, includes OCI version/revision labels, and exposes
|
|
API port 8010 plus MCP port 8011.
|
|
|
|
```bash
|
|
docker build -f Containerfile \
|
|
--build-arg VERSION=0.2.0 \
|
|
--build-arg VCS_REF="$(git rev-parse HEAD)" \
|
|
-t hub-core:dev .
|
|
|
|
docker run --rm -p 8010:8010 \
|
|
-e HUB_CORE_ALLOW_EPHEMERAL=1 \
|
|
hub-core:dev
|
|
```
|
|
|
|
Deployment charts, secrets, rollout policy, and live evidence remain owned by
|
|
the rapp/platform repositories. `/api/v2` data and compatibility routes remain
|
|
on Core Hub until the T06/CORE-WP-0010 dual-run slices move them.
|
|
|
|
## Conformance
|
|
|
|
The public-port Tier 2/3 scaffold is documented in `docs/conformance.md`. Run
|
|
it against an isolated runtime with `hub-core conformance --base-url <url>`.
|
|
|
|
## Core Hub absorption
|
|
|
|
`docs/core-hub-absorption-plan.md` defines the capability-sized `/api/v2`
|
|
route and data move order, single-writer dual-run controls, evidence gates,
|
|
rollback, and final cutover criteria shared with `CORE-WP-0010`.
|