Record the verified publisher image digest and track wrapper rollout separately. Register existing CORE-WP, DISCTL-WP, and REPO-WP owners and retain the outstanding instruction correction. Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a100de-2e1c-7e23-9ae9-2da0e0499411
5.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.
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.
Deliver registry corrections
Containerfile copies the committed registry into the publisher image. A Git
push or rmgr sync updates source/work-record projections; it does not refresh
the registry in an already running publisher. After a repository rename:
- Verify the canonical Forgejo
full_nameand preserve the registrar UUID. - Update the registry coordinates, commit, and build an image from that clean
commit with
make container-build IMAGE_TAG=<full-commit-sha>. - Verify the embedded registry and observe the renamed sources from the image, then push the image and record its immutable digest.
- Track the deployment in the consuming wrapper (
rapp-core-hub). Pin the new digest and deploy through its approved release procedure, then runmake verify-publisherbefore enablingpublisher.connectCandidate.
Keep the exact identity check strict: an old Forgejo URL redirecting to a new
repository name is evidence to update the registry, not permission to silently
change published identity. Source correction and live rollout need separate
completion evidence. The October 3 refresh is tracked in RMGR-WP-0018.
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.