From c65cc4ec1e3b63b57c77555cc0c8ab6459721bf7 Mon Sep 17 00:00:00 2001 From: tegwick Date: Sun, 6 Sep 2026 19:48:55 +0200 Subject: [PATCH] Register CANP-WP-0006: hosted registry and index service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Toward a production deployment as rapp-canned-prompts on railiance01. A rapp repo packages a deployable its ownership_repo already produces — rapp.yaml pins upstream_components.version to a container digest. canned-prompts has no deployable: a CLI with no HTTP surface, no image, no database. A rapp pointing at nothing is a stub that tells the fleet's tooling a deployment exists when none does. So the service comes first, and rapp-canned-prompts is created once there is a digest to pin. Decisions recorded: hosted registry plus index as the v1 surface, the service living in canned-prompts so rapp.yaml gets ownership_repo: canned-prompts (the sbom-nexus shape), and deployment as a platform service whose data is nevertheless tenant-keyed from the first migration per business-app-service-contract section 1.3 — cheap now, a rewrite later. Stack matches state-hub and sbom-nexus: FastAPI, SQLAlchemy, Alembic, PostgreSQL. The deployment guide additionally requires unauthenticated /healthz and /readyz. INTENT's deliberate boundary still holds: the service hosts packages and does not become an agent runtime. reference/ stays untouched and dependency-light as the format's conformance witness. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Bjefh8NUiEiahN4JLwoSKM EOF Assistant: claude-code Assistant-Model: opus Assistant-Process: 388925@bnt-lap001 Assistant-Session: 3507023f-e0fd-4a1e-9d90-a0d4217d1502 --- .../CANP-WP-0006-hosted-registry-service.md | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 workplans/CANP-WP-0006-hosted-registry-service.md diff --git a/workplans/CANP-WP-0006-hosted-registry-service.md b/workplans/CANP-WP-0006-hosted-registry-service.md new file mode 100644 index 0000000..3386355 --- /dev/null +++ b/workplans/CANP-WP-0006-hosted-registry-service.md @@ -0,0 +1,157 @@ +--- +id: CANP-WP-0006 +type: workplan +title: "Hosted registry and index service" +domain: agents +repo: canned-prompts +status: proposed +owner: codex +topic_slug: practice +created: "2026-09-06" +updated: "2026-09-06" +--- + +# Hosted registry and index service + +Toward a production deployment on railiance01 as `rapp-canned-prompts`. + +**Sequencing finding.** A `rapp-*` repo packages and operates a deployable its +`ownership_repo` already produces — `declarations/rapp.yaml` pins +`upstream_components.version` to a container digest. `canned-prompts` has no +deployable: a CLI module with no HTTP surface, no image, no database. A rapp +whose `upstream_components` points at nothing is a stub that tells the fleet's +tooling a deployment exists when none does. The service comes first. + +**Decisions (operator, 2026-09-06):** + +- *Hosted registry plus index* is the v1 surface. § 20 already permits an HTTP + registry and § 20.3's index is the query surface, so this validates INTENT + principle 10's "registry-ready" claim rather than inventing a new concept. +- *The service lives in `canned-prompts`*, so `rapp.yaml` gets + `ownership_repo: canned-prompts` — the `sbom-nexus` shape, where product + ownership stays out of the operations repo. +- *Platform service, tenant-keyed regardless.* Deployed as a platform service + like `sbom-nexus`, but all owned data is keyed by tenant from the first + migration. `business-app-service-contract_v0.1` § 1.3 makes that mandatory so + a later consolidation is a data-copy rather than a rewrite; a collaborative + prompting platform will need it, and retrofitting is the expensive path. +- *Service first, rapp when there is a digest to pin.* + +**Stack**, matching `state-hub` and `sbom-nexus`: FastAPI, uvicorn, SQLAlchemy, +Alembic, Pydantic, PostgreSQL. `RailianceAppDeploymentGuide.md` additionally +requires unauthenticated `/healthz` and `/readyz`. + +**Boundary.** The service hosts packages; it does not become an agent runtime. +`INTENT.md`'s deliberate boundary still holds — no model execution, no +orchestration. Rendering stays deterministic, and `derive` stays a declaration +the service does not satisfy. + +## Service skeleton and health surface + +```task +id: CANP-WP-0006-T01 +status: todo +priority: high +``` + +A `service/` package inside this repo: FastAPI application factory, settings +via pydantic-settings, and the health surface the deployment guide requires — +unauthenticated `/healthz` and `/readyz`, plus `/state/health` for consistency +with `state-hub` and `sbom-nexus`. + +`/readyz` must actually check the database, not return 200 unconditionally. A +readiness probe that cannot fail is a liveness probe with a misleading name. + +Keep `reference/` untouched. It is the format's conformance witness and must +stay dependency-light; the service is a separate consumer of the same package +semantics. + +## Tenant-keyed schema and first migration + +```task +id: CANP-WP-0006-T02 +status: todo +priority: high +``` + +Alembic migration `0001` creating the store. Every table holding owned data +carries a tenant key from this migration onward — packages, versions, and index +entries — per the service contract § 1.3. No business logic may assume it is +the only tenant (§ 1.4). + +Model the three things the format already distinguishes, and do not conflate +them: + +- **package version** — immutable content addressed by `@` + (§ 17), scoped to a registry because identity is registry-scoped (§ 3.2); +- **index entry** — how a version arrived in this store (§ 20.3): source, + method, `included_at` which is never overwritten, `last_seen_at`; +- **manifest fields** worth indexing for discovery — name, summary, tags, + license, type. + +Store package files as content, not as rows per file. + +## Read API + +```task +id: CANP-WP-0006-T03 +status: todo +priority: high +``` + +`GET /packages` (search over id, name, summary, tags), `GET /packages/{id}` +(versions), `GET /packages/{id}/{version}` (manifest), +`GET /packages/{id}/{version}/archive` (the package files), and +`GET /index` (§ 20.3 entries). + +Ambiguity is reported, never guessed (§ 3.2): a bare id matching packages from +more than one registry returns the candidates, not a choice. + +## Publish API + +```task +id: CANP-WP-0006-T04 +status: todo +priority: high +``` + +`POST /packages` accepting a package, validating it with the same rules as the +CLI, and refusing a re-publish of an existing `@` with different +content (§ 17). Strict packaging applies: reserved paths and manifest-referenced +files only (§ 2). + +Namespace policy (§ 20.1) is enforced here rather than advised, because unlike a +filesystem registry a service *can* authenticate a publisher. Note what identity +mechanism it uses; if there is none yet, say so and refuse writes rather than +accepting anonymous publishes into a closed namespace. + +## HTTP registry in the reference CLI + +```task +id: CANP-WP-0006-T05 +status: todo +priority: medium +``` + +Teach `--registry` to accept an `https://` URL, so `publish` and `install` work +against the service. § 20 already allows an HTTP registry; this is the first +implementation of one, and the first real test of whether package semantics +survive a transport change unmodified — which is what INTENT principle 10 +claims. + +If they do not survive it, that is a finding about the format, not a bug to +paper over in the client. + +## Image and smoke contract + +```task +id: CANP-WP-0006-T06 +status: todo +priority: medium +``` + +Dockerfile and a published image, plus the checks a `rapp` smoke contract will +assert: health ok, migration at head, private service only, image digest match. + +Completing this produces the digest that `rapp-canned-prompts` needs to pin, at +which point that repo can be created against something real.