repo-manager/docs/repository-classification-publisher.md
tegwick 54271a2261 feat: publish repository classification projections
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a053ff-1d6f-7fe2-ac1c-a6eb40a42a0c
2026-09-01 00:48:32 +02:00

3.9 KiB

Repository classification publisher

Repo Manager publishes the frozen helixforge.repository-classification-projection 1.0.0 envelope at:

GET /ports/repositories/classifications?cursor=<opaque>

The route is read-only. It contains registrar UUID, slug, lifecycle, classification, Git revision, source fingerprint, and observation time. Local paths, remotes, work records, source bodies, and credentials never enter the envelope.

Private operator registry

Publication joins repository-owned .repo-classification.yaml files to a private operator registry. The registry is local runtime state because checkout paths are host-specific; do not commit it. Its schema is:

schema: repo-manager.repository-registry.v1
repositories:
  - repository_id: a9d105c6-10fa-4cf9-8bc1-e248476698d3
    slug: repo-manager
    lifecycle: active
    path: /home/operator/repo-manager

Bootstrap current stable identities from the retiring primary State Hub:

rmgr publisher import-registry \
  --root /home/operator \
  --api-base http://127.0.0.1:8000 \
  --output ~/.repo-manager/repository-registry.yaml

The import verifies instance_role=primary, discovers only classified Git working copies below the selected root, and uses bounded direct identity reads. It does not use State Hub's expensive bulk repository projection and does not trust State Hub host paths. Transient reads retry; locally classified but unregistered checkouts are retained as warnings and omitted rather than being assigned invented identities. Any other failure prevents replacement of the registry file.

After repository-registry authority moves fully into Repo Manager, normal governed registration maintains this same private schema and the bootstrap command can be retired. The publisher contract does not change.

Run

Set runtime configuration through the environment:

REPO_MANAGER_REGISTRY_PATH=~/.repo-manager/repository-registry.yaml
REPO_MANAGER_CURSOR_SECRET=<at-least-32-byte-secret>
REPO_MANAGER_API_TOKEN=<optional-bearer-token>
REPO_MANAGER_PROJECTION_PAGE_SIZE=100
REPO_MANAGER_PROJECTION_MAX_SNAPSHOTS=4

Secret values belong in the platform credential path and must not be committed or logged. Start the API with:

rmgr publisher api --host 0.0.0.0 --port 8020

GET /healthz is process liveness. GET /readyz verifies that configuration and the registry are usable. When REPO_MANAGER_API_TOKEN is set, the projection route requires the matching bearer token.

Snapshot and failure semantics

A first-page request observes the complete registry into an immutable in-memory snapshot. Repositories are ordered by registrar UUID. Subsequent page cursors carry snapshot ID, offset, and page size protected by HMAC-SHA256. Only a small bounded set of in-flight snapshots is retained; an invalid, tampered, or expired cursor returns 409.

Missing checkouts, invalid classifications, or unavailable Git revisions are emitted as bounded error diagnostics. Hub-core rejects any such transfer and keeps the last accepted generation, so a partial observation never becomes the active navigation projection.

Hub-core client

Configure the hub-core runtime with:

HUB_CORE_REPO_MANAGER_BASE_URL=http://repo-manager:8020
HUB_CORE_REPO_MANAGER_API_TOKEN=<same-optional-bearer-token>
HUB_CORE_REPO_MANAGER_TIMEOUT_SECONDS=10
HUB_CORE_REPO_PROJECTION_REFRESH_SECONDS=300

Hub-core refreshes once at startup and then on the configured interval. A failed refresh marks the dependency stale while preserving the last accepted generation. Setting the refresh interval to 0 disables the background loop.

Verification

make test
make publisher-snapshot \
  REGISTRY=~/.repo-manager/repository-registry.yaml \
  CURSOR_SECRET='<runtime-secret>'

RMGR-WP-0013's live conformance used five pages of 25 rows. Hub-core accepted all 123 registered classifications atomically and produced one current generation; no State Hub classification table was read by the publisher.