Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a053ff-1d6f-7fe2-ac1c-a6eb40a42a0c
4.8 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.
Forgejo-backed registry
Publication joins repository-owned .repo-classification.yaml files to a
stable repository registry. Production uses the committed
config/repository-registry.yaml; it contains registrar UUIDs and canonical
Forgejo identities, but no credentials or host paths:
schema: repo-manager.repository-registry.v1
repositories:
- repository_id: a9d105c6-10fa-4cf9-8bc1-e248476698d3
slug: repo-manager
lifecycle: active
forgejo_repository: coulomb/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 \
--source forgejo \
--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.
The import is a migration/bootstrap path. Normal governed registration must maintain the committed UUID-to-Forgejo mapping after State Hub registrar retirement. 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_FORGEJO_BASE_URL=https://forgejo.coulomb.social
REPO_MANAGER_FORGEJO_TOKEN_FILE=/var/run/secrets/repo-manager/forgejo/token
REPO_MANAGER_FORGEJO_WORKERS=8
REPO_MANAGER_FORGEJO_TIMEOUT_SECONDS=10
REPO_MANAGER_FORGEJO_RETRIES=2
REPO_MANAGER_PROJECTION_PAGE_SIZE=100
REPO_MANAGER_PROJECTION_MAX_SNAPSHOTS=4
The Forgejo token is optional for public repositories and required for private
repositories. It must have only read:repository; mount it from the platform
credential path rather than putting it in an environment value, Git, or logs.
The cursor secret may be omitted for a single-replica runtime, in which case a
fresh process-local key is generated and in-flight cursors expire on restart.
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.
For each repository the publisher reads metadata, resolves the default branch
to an exact commit SHA, and then reads .repo-classification.yaml at that SHA.
Missing/private repositories, invalid classifications, or unavailable
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>'
The workstation conformance accepted all 123 local classifications. Forgejo
conformance resolves 114 public repositories without credentials and correctly
rejects the nine private rapp-* sources until a least-privilege source-read
token is mounted. No State Hub classification table is read at runtime.