135 lines
4.7 KiB
Markdown
135 lines
4.7 KiB
Markdown
|
|
---
|
||
|
|
id: RCP-WP-0002
|
||
|
|
type: workplan
|
||
|
|
title: "First deployment of canned-prompts on Railiance"
|
||
|
|
domain: agents
|
||
|
|
repo: rapp-canned-prompts
|
||
|
|
status: proposed
|
||
|
|
owner: codex
|
||
|
|
topic_slug: practice
|
||
|
|
created: "2026-09-06"
|
||
|
|
updated: "2026-09-06"
|
||
|
|
state_hub_workstream_id: "11874f32-ac36-5bb9-a0a5-e7a259f5972c"
|
||
|
|
---
|
||
|
|
|
||
|
|
# First deployment of canned-prompts on Railiance
|
||
|
|
|
||
|
|
The package is written and validated; what remains needs credentials and a
|
||
|
|
published image, which are operator actions rather than authoring ones.
|
||
|
|
|
||
|
|
`readiness_state` is `draft` and stays there until T04 produces evidence.
|
||
|
|
Topology is not readiness (ADR-0006): binding this rapp to a reef does not make
|
||
|
|
it deployed.
|
||
|
|
|
||
|
|
## Publish the image and pin its digest
|
||
|
|
|
||
|
|
```task
|
||
|
|
id: RCP-WP-0002-T01
|
||
|
|
status: todo
|
||
|
|
priority: high
|
||
|
|
state_hub_task_id: "3e7faf50-8fe9-5ef3-8a75-1d9e586d6c0f"
|
||
|
|
```
|
||
|
|
|
||
|
|
`declarations/rapp.yaml` carries `version: pending-publication`, and both
|
||
|
|
manifests carry a matching tag. This is deliberate: a placeholder shaped like a
|
||
|
|
real digest could be mistaken for something deployable, and a rapp that pins
|
||
|
|
nothing is a stub that tells the fleet tooling a deployment exists when none
|
||
|
|
does.
|
||
|
|
|
||
|
|
The image builds and was verified locally in `canned-prompts`
|
||
|
|
(`CANP-WP-0006-T06`): it starts non-root, all six service-level smoke checks
|
||
|
|
pass against the running container, and the reference CLI installs a package
|
||
|
|
from it over HTTP.
|
||
|
|
|
||
|
|
What remains is publication to `forgejo.coulomb.social/coulomb/canned-prompts`,
|
||
|
|
which needs registry credentials. Then replace `pending-publication` in
|
||
|
|
`declarations/rapp.yaml`, `manifests/runtime.yaml` and `manifests/migration.yaml`
|
||
|
|
with the `@sha256:` digest — the same digest in all three, since
|
||
|
|
`live-image-digest-match` compares them.
|
||
|
|
|
||
|
|
## Provision database roles and credentials
|
||
|
|
|
||
|
|
```task
|
||
|
|
id: RCP-WP-0002-T02
|
||
|
|
status: todo
|
||
|
|
priority: high
|
||
|
|
state_hub_task_id: "61f5cbd7-8fcf-5156-87da-57239ae55d8f"
|
||
|
|
```
|
||
|
|
|
||
|
|
Two roles, deliberately separate: a runtime role that reads and writes rows, and
|
||
|
|
a migration role that owns the schema. A service able to `ALTER` its own tables
|
||
|
|
at runtime turns any code defect into a schema defect.
|
||
|
|
|
||
|
|
Needed from `rapp-postgres` and the credential broker:
|
||
|
|
|
||
|
|
- database `canned_prompts` on `platform-pg-2`;
|
||
|
|
- `creds/canned-prompts-runtime` and `creds/canned-prompts-migration` in OpenBao
|
||
|
|
under the `database` path;
|
||
|
|
- the `openbao-canned-prompts-eso-token` secret in `external-secrets`.
|
||
|
|
|
||
|
|
`creds/canned-prompts-publish` is **optional**. Without it the service is
|
||
|
|
read-only, which is the correct posture until per-publisher identity exists —
|
||
|
|
not a misconfiguration to be worked around.
|
||
|
|
|
||
|
|
## Apply and migrate
|
||
|
|
|
||
|
|
```task
|
||
|
|
id: RCP-WP-0002-T03
|
||
|
|
status: todo
|
||
|
|
priority: high
|
||
|
|
state_hub_task_id: "0b8d206e-bd28-5950-abf7-d824015c09a4"
|
||
|
|
```
|
||
|
|
|
||
|
|
Order matters, and the ordering is the point rather than a convenience:
|
||
|
|
|
||
|
|
1. `manifests/00-namespace.yaml` — the `railiance.io/postgres-client` label is
|
||
|
|
what lets the database namespace accept traffic;
|
||
|
|
2. `manifests/database-secrets.yaml`, then wait for the secrets to materialize;
|
||
|
|
3. `manifests/migration.yaml` — the Job runs `alembic upgrade head` under the
|
||
|
|
migration role and must complete before any replica serves;
|
||
|
|
4. `manifests/runtime.yaml`.
|
||
|
|
|
||
|
|
The runtime deliberately does not migrate at start-up. Migrations as a Job keep
|
||
|
|
a schema rollback separate from a code rollback and stop replicas racing each
|
||
|
|
other.
|
||
|
|
|
||
|
|
## Verify and record evidence
|
||
|
|
|
||
|
|
```task
|
||
|
|
id: RCP-WP-0002-T04
|
||
|
|
status: todo
|
||
|
|
priority: high
|
||
|
|
state_hub_task_id: "6d9eb97c-57e2-5b74-b6eb-455076713417"
|
||
|
|
```
|
||
|
|
|
||
|
|
Run `tools/smoke.sh`. It checks what only the cluster can answer — secrets
|
||
|
|
materialized, Service is ClusterIP with no Ingress, NetworkPolicies present,
|
||
|
|
live image digest matches the pin — and calls `canned-prompts`'
|
||
|
|
`service/tools/smoke.py` for health and migration head rather than holding a
|
||
|
|
second opinion about whether the service is healthy.
|
||
|
|
|
||
|
|
Record the output as evidence, then move `readiness_state` to `deployed`, and to
|
||
|
|
`verified` only with that evidence attached.
|
||
|
|
|
||
|
|
## Decide per-publisher identity
|
||
|
|
|
||
|
|
```task
|
||
|
|
id: RCP-WP-0002-T05
|
||
|
|
status: wait
|
||
|
|
priority: medium
|
||
|
|
state_hub_task_id: "1252f3a1-12ce-5bc1-b003-3e8999d03459"
|
||
|
|
```
|
||
|
|
|
||
|
|
Blocked on a decision in `canned-prompts`, recorded here because it is the
|
||
|
|
thing that decides what this deployment is *for*.
|
||
|
|
|
||
|
|
Today the service authenticates a single shared bearer token proving "the
|
||
|
|
operator". That is adequate for a private in-cluster registry and inadequate for
|
||
|
|
the collaborative prompting platform the operator described: every token holder
|
||
|
|
is indistinguishable, so § 20.1 namespace ownership can be enforced against
|
||
|
|
anonymous callers but not attributed among publishers.
|
||
|
|
|
||
|
|
This repo must not paper over that with cluster configuration implying finer
|
||
|
|
control than exists. When identity lands upstream, revisit the publish-token
|
||
|
|
secret and the NetworkPolicy ingress rule, which currently admits any namespace.
|