Finish RAILIANCE-WP-0021: family schemas, validator, and ADR-0007

Add rail and reef schemas, derive reef bound_rapps from rapp.bound_reefs,
and ship a standalone family-declaration validator with an inventory-fed
coverage check. Point the bootstrap contract at the schemas, record the
dimension and cardinality decisions in ADR-0007, correct the first-wave
candidates document, and release the shape to downstream repos.
This commit is contained in:
codex 2026-08-13 15:29:07 +02:00
parent d3b3512a60
commit 3cc0dc31d6
20 changed files with 1509 additions and 187 deletions

View file

@ -1,15 +1,48 @@
# First-Wave `rapp-*` Candidates
Date: 2026-07-25
Updated: 2026-08-13 (RAILIANCE-WP-0021-T08)
## Purpose
Choose and order the first `rapp-*` candidates for Railiance.
Choose and order the first `rapp-*` candidates for Railiance, and record
what was actually built against that plan.
`rapp-*` repos are for managed workload packaging and scaffolding. They are not
new ownership homes. The decision here is therefore not "which repos are
important?" but "which workloads already have a strong enough package boundary
to become first-class managed wrappers without weakening ownership?"
`rapp-*` repos are for managed workload packaging and scaffolding. They are
not new ownership homes. The decision is not "which repos are important?"
but "which workloads already have a strong enough package boundary to become
first-class managed wrappers without weakening ownership?"
## What Was Actually Built
The 2026-07-25 plan was:
1. `rapp-openbao`
2. `rapp-vergabe-teilnahme`
3. `rapp-forgejo` after the forge runtime target stabilized
What exists on 2026-08-13:
| Repo | Status | How it arrived |
|---|---|---|
| `rapp-openbao` | live, declared | as planned |
| `rapp-postgres` | live, declared | ad hoc, from the need for a shared platform database |
| `rapp-qonto` | live, declared | ad hoc, from the need to run Qonto on `rail-knative` |
| `rapp-vergabe-teilnahme` | never built | the user-facing wrapper it existed to prove is unproven |
| `rapp-forgejo` | not built | forge placement is now decided (`d151d817`): workload to `rapp-forgejo`, layer to S4 |
| `rapp-secrets-engine` | exists, undeclared | family prefix, no `declarations/` |
| `rapp-tenant-engine` | exists, undeclared | family prefix, no `declarations/` |
| `rapp-user-engine` | exists, undeclared | family prefix, no `declarations/` |
The platform-service pattern is proven twice (`rapp-openbao`,
`rapp-postgres`). The user-facing wrapper pattern is unproven. That is the
consequence of building to immediate need instead of to the planned second
slot.
The operator decision that follows is: build `rapp-vergabe-teilnahme` to
prove the user-facing shape before mass extraction. Do not treat the three
engine repos, or any other live undeclared workload, as a substitute for
that proof.
## Selection Criteria
@ -23,147 +56,159 @@ The first-wave candidates should satisfy most of the following:
- low ambiguity between packaging ownership and domain ownership
- good demonstration value for later `rapp-*` extractions
## Assessed Candidates
## Planned First-Wave Assessment (2026-07-25)
The original assessment is kept below so the gap between plan and outcome
stays visible. It is not the current worklist.
### 1. OpenBao from `railiance-platform`
Assessment: **choose first**
Assessment: **choose first** — and this one landed.
Why it fits:
Why it fitted:
- It is a clear third-party upstream product with durable identity.
- The workload already has a substantial Railiance packaging surface:
`helm/openbao-values.yaml`, middleware, UI overlay assets, deploy/verify
scripts, and operator runbooks.
- The repo already distinguishes between the OpenBao workload itself and the
wider S3 platform policy that consumes it.
- It is important enough to prove that `rapp-*` is not only for user-facing
apps; platform services can also be managed workloads.
- The workload already had a substantial Railiance packaging surface.
- The repo already distinguished the OpenBao workload from the wider S3
platform policy that consumes it.
- It proved that `rapp-*` is not only for user-facing apps.
What should move into `rapp-openbao`:
- Helm values and Kubernetes-facing package assets for the OpenBao workload
- UI overlay wrapper assets
- generic deploy, verify, and workload-health runbooks
- workload-specific smoke and recovery expectations
What should remain in `railiance-platform`:
- the S3 ownership of secrets custody as a platform capability
- workload lane policy, credential approval, and platform-wide access models
- cross-workload secret-delivery conventions consumed by many workloads
Conclusion:
`rapp-openbao` should be the first `rapp-*` extraction.
What stayed in `railiance-platform`: secrets custody as a platform
capability, lane policy, credential approval, and cross-workload
secret-delivery conventions.
### 2. Forge workload from `railiance-forge`
Assessment: **defer from first wave**
Assessment then: **defer from first wave**. That deferral still holds as a
first-wave fact, but the placement question is now closed. Decision
`d151d817` puts the Forgejo workload in `rapp-forgejo` and the layer
responsibility (runner placement and labels, registry retention, artifact
lifecycle, package credentials) in S4 `railiance-enablement`.
`railiance-forge` is placed, not retired. Gitea is confirmed replaced.
Why it is not first:
- The current live workload is still Gitea on CoulombCore.
- The intended production direction is Forgejo on Railiance01.
- Packaging identity is therefore not stable enough yet: extracting now would
either enshrine a temporary Gitea compatibility package or pretend the
Forgejo cutover is already complete.
- The runtime and migration story still spans current Gitea operation, future
Forgejo deployment, runner substrate, registries, and cutover sequencing.
Decision:
- Do **not** make the forge workload the first `rapp-*` extraction.
- Prefer `rapp-forgejo` as the eventual target package once the production
direction is the real operating target.
- Create `rapp-gitea` only if Railiance discovers it needs a long-lived
compatibility wrapper for the current workload rather than a short migration
bridge.
What this means:
- `railiance-forge` keeps runtime ownership for now.
- The forge wrapper should follow after the current Gitea-versus-Forgejo
packaging identity stops moving.
Conclusion:
The forge workload is packaging-worthy, but it should not be first-wave
`rapp-*`.
`rapp-forgejo` is therefore a wave-2 package with a decided home, not an
open placement debate.
### 3. User-facing S5 workload from `railiance-apps`
Assessment: **choose `vergabe-teilnahme` for wave 1**
Assessment then: **choose `vergabe-teilnahme` for wave 1**. It was never
built. The reasons it was the right user-facing slot remain: one named
workload, explicit release surface, secret handling that is not entangled
with shared platform semantics. That is why it is still the package that
must prove the user-facing shape before mass extraction.
Why `vergabe-teilnahme` wins the S5 slot:
`reuse-surface` remains the strongest follow-on self-built service
candidate. `core-hub` should still wait.
- It is clearly user-facing and already operates as one named workload package.
- Its release surface is explicit: chart, values, ingress, deployment targets,
migration command, smoke checks, and operator runbook.
- Secret handling is clear without being entangled with shared platform
semantics: app credentials are consumed from Kubernetes Secrets and the app
env secret is locally rebuilt by operator procedure.
- It is simpler and more stable than the current Core Hub / Inter-Hub history
and more obviously user-facing than service-style workloads such as
`reuse-surface`.
## Wave-2 Inventory
What should move into `rapp-vergabe-teilnahme`:
Grouped by bounded context, in the composition shape from ADR-0007. These
are indicative packages, not created repos. A package is listed only where
members share rollout and rollback fate. Names that already exist as
undeclared `rapp-*` repos are marked so they are not invented twice.
- the chart and workload values
- the ingress and app-specific release runbook
- workload-specific rollout, migration, smoke, and rollback guidance
- workload-specific secret consumption contract
### `rapp-vergabe-teilnahme` — prove the user-facing wrapper
What should remain in `railiance-apps`:
```yaml
composition:
purpose: Package the Vergabe Teilnahme application as a managed user-facing workload.
member_repos:
- repo: vergabe-teilnahme
role: application source and chart
deployables: [vergabe-teilnahme]
```
- S5 ownership of generic application release patterns
- reusable onboarding and operator recipes
- cross-app S5 guardrails that should not be duplicated per workload package
Build this before any further user-facing extraction.
Second-wave S5 note:
### `rapp-forgejo` — decided placement
- `reuse-surface` is the strongest follow-on self-built service candidate after
`vergabe-teilnahme`, because it already shows explicit OpenBao-backed runtime
secret lanes and a tidy single-workload chart surface.
- `core-hub` and retired `inter-hub` should wait because their packaging
history is still entangled with cutover and legacy service evolution.
```yaml
composition:
purpose: Package Forgejo, its runner, and the package registry as one managed forge.
member_repos:
- repo: railiance-forge
role: operational helm, manifests, runner, and registry assets
deployables: [forgejo, forgejo-runner, forgejo-registry]
```
Conclusion:
Layer concerns stay in `railiance-enablement`. Do not create `rapp-gitea`.
`rapp-vergabe-teilnahme` should be the first user-facing S5 `rapp-*`.
### `rapp-netkingdom-identity` — identity bounded context
## First-Wave Order
```yaml
composition:
purpose: Package NetKingdom identity — users, tenants, SSO, MFA, and authorization — as one rollback unit.
member_repos:
- repo: user-engine
role: user identity
deployables: [user-engine]
- repo: tenant-engine
role: tenant identity
deployables: [tenant-engine]
- repo: key-cape
role: SSO and MFA
deployables: [keycloak]
- repo: flex-auth
role: authorization decisions
deployables: [flex-auth]
```
The recommended order is:
`rapp-user-engine` and `rapp-tenant-engine` already exist as undeclared
prefix claims. They are not separate rapps under grouped-by-bounded-context
granularity. Their owners should either fold them into this package or
justify an independent rollback fate and then declare them. `rapp-secrets-engine`
is the same question against `rapp-openbao` / `railiance-platform`, not a
fourth identity member.
1. `rapp-openbao`
2. `rapp-vergabe-teilnahme`
3. `rapp-forgejo` after the forge runtime target is stable enough to avoid
immediate rename or migration churn
### `rapp-coulomb-social`
This order is intentional.
```yaml
composition:
purpose: Package the Coulomb Social application as a managed user-facing workload.
member_repos:
- repo: coulomb-social
role: application
deployables: [coulomb-social]
```
- `rapp-openbao` proves the third-party platform-service wrapper model.
- `rapp-vergabe-teilnahme` proves the self-built user-facing app wrapper model.
- The forge wrapper then follows with a clearer target identity and after the
first two wrappers have established the pattern.
Do not start this until `rapp-vergabe-teilnahme` has proven the user-facing
shape.
### `rapp-helix-forge`
```yaml
composition:
purpose: Package the Helix Forge methodological workspace as a managed workload.
member_repos:
- repo: helix-forge
role: capability-first development ecosystem
deployables: [helix-forge]
```
Helix Forge is a different lineage from `railiance-forge`. It is not a
rename of `rapp-forgejo`.
## Risks To Watch
- If `rapp-openbao` absorbs platform-wide policy and credential-governance
logic, the wrapper will become a shadow S3 repo.
- If `rapp-vergabe-teilnahme` absorbs generic S5 onboarding or app recipes, it
will weaken `railiance-apps` as the shared S5 release home.
- If the forge wrapper is extracted too early, Railiance will immediately face
a Gitea-versus-Forgejo package rename or parallel-wrapper problem.
logic, the wrapper becomes a shadow S3 repo.
- If `rapp-postgres` is asked to mint the backup account, key, or bucket, a
consumed destination is being mistaken for package ownership. The bucket
is `resource-control` (`RESOURCE-WP-0002`); the credential is
`railiance-platform` OpenBao custody; purchase is decision `9c21c0e0`.
- If `rapp-vergabe-teilnahme` absorbs generic S5 onboarding, it weakens
`railiance-apps`.
- If the three undeclared engine repos are treated as rapps without a
declaration, the coverage check cannot see them and will list their live
deployables as uncovered.
- If wave-2 extraction starts before the user-facing wrapper is proven,
Railiance will mass-produce the platform-service shape and still not know
whether the other shape works.
## Outcome
Railiance now has a concrete first-wave `rapp-*` sequence:
- first `rapp-openbao`
- then `rapp-vergabe-teilnahme`
- then the forge wrapper once the production package identity is stable
That is enough to start repo-local extraction planning without pretending every
workload needs its own `rapp` immediately.
Wave 1 proved the platform-service wrapper, twice, and did not prove the
user-facing wrapper. The next package that must exist is
`rapp-vergabe-teilnahme`. Everything else in the wave-2 inventory waits on
that proof, on owner-side declaration of the three undeclared prefix
claims, and on the schema migration owned by `RAILIANCE-WP-0015-T02`.