Establish Railiance architecture home

This commit is contained in:
codex 2026-07-25 10:54:37 +02:00
parent dd54aee0da
commit 8022665b35
22 changed files with 2925 additions and 1 deletions

View file

@ -0,0 +1,133 @@
# ADR-0001: Repository Prefix Architecture
Date: 2026-07-25
Status: Accepted
## Context
Railiance already has a meaningful set of ownership repos such as
`railiance-infra`, `railiance-cluster`, `railiance-platform`,
`railiance-enablement`, `railiance-apps`, `railiance-forge`, and
`railiance-fabric`.
That structure is useful, but it does not by itself capture all of the
dimensions Railiance now needs.
In particular, the architecture needs clear source-controlled homes for:
- workload execution contracts across different operations architectures,
- managed workload packages as first-class repos,
- and concrete substrate boundaries such as named servers, workstations, or
grouped environments.
Without that separation, Kubernetes-specific workload semantics remain mixed
into `railiance-cluster`, workload wrappers remain mixed into ownership repos,
and concrete substrates remain under-described.
Railiance also operates inside a wider ecosystem around Railiance, Net Kingdom,
and the Helix Forge software factory. That wider context needs architecture
that can support both exploratory operation and production-grade evolution
without leaving key responsibilities ambiguous.
## Decision
Railiance adopts four canonical repository families:
1. `railiance-*` for ownership and responsibility areas
2. `rail-*` for workload execution contracts
3. `rapp-*` for Railiance-managed workload packages
4. `reef-*` for durable substrate boundaries
The current implementation wave is explicitly centered on `rail-kubernetes` as
the default base rail. Additional rails are introduced only when a concrete
workload has a sound reason to run on a distinct execution architecture.
`rail-knative` is the first expected follow-on rail, motivated by the need to
support `qonto-assistent`, but it should follow the `rail-kubernetes` boundary
cleanup rather than bypass it.
## Meaning Of Each Family
### `railiance-*`
Owns major architectural responsibilities, shared policies, and durable layer
boundaries.
### `rail-*`
Owns how workloads run on a specific execution architecture such as Kubernetes,
Knative, KEDA, Fission, or Nuclio.
In the current phase, `rail-kubernetes` is the default path for platform
services and managed applications.
### `rapp-*`
Owns the managed workload package for one service or application, whether it is
an internal workload or a wrapped upstream product.
Its role is to provide the managed wrapper and scaffolding needed to run that
workload in the Railiance and Net Kingdom context. It does not replace
responsibility ownership.
### `reef-*`
Owns the concrete substrate reality where rails and `rapp`s are bound, such as
a named server, cluster, workstation, or grouped substrate class.
A reef is about purpose-bound compute resources, not merely about individual
machines.
## Consequences
### Positive
- Ownership, execution, workload identity, and substrate identity become
separate concerns.
- Railiance can support multiple execution architectures without forcing all
workload semantics into `railiance-cluster`.
- Platform services and applications can both become first-class managed
workload packages where appropriate.
- Concrete substrates gain a clear architectural home without overloading the
ownership repos.
- The framework gains a disciplined default path for introducing new rails
instead of proliferating them speculatively.
### Required Follow-On Work
- Define the initial `rail-*` contracts, starting with `rail-kubernetes`.
- Evolve the current `railiance/app.toml` and overlay pattern into a
rail-aware, eventually rail-neutral workload packaging contract.
- Identify which current workloads should become `rapp-*` repos.
- Extend `railiance-fabric` so rails, `rapp`s, and reefs become graph-native.
- Define when mixed-rail reefs are acceptable and when clearer substrate
separation should be preferred.
### Constraints
- `reef-*` must not become a default one-repo-per-machine pattern.
- Generic logic stays in the appropriate ownership repo.
- A named machine gets its own reef only when that machine is itself a durable
substrate boundary.
- `rapp-*` repos must not become shadow ownership repos.
- Transitional substrate labels should not be canonized before the pattern is
operationally stable.
## Current Interpretation For Existing Repos
- `railiance-*` repos remain the primary ownership axis.
- Current workload-execution logic in `railiance-cluster` is a candidate to
migrate into `rail-kubernetes`.
- Current workload wrappers inside `railiance-apps`, `railiance-platform`, or
`railiance-forge` may evolve into `rapp-*` repos over time.
- Current named substrates such as COULOMBCORE, RAILIANCE01, and WORKSTATION
may justify `reef-*` repos when they represent real operational boundaries.
- A reef may host more than one rail in early or mixed environments, but
production-critical substrates should prefer clearer purpose and primary-rail
boundaries unless a mixed design is justified.
## Notes
This ADR defines the repository taxonomy. It does not yet mandate a full
migration or rename of existing repos. Migration should happen when it produces
clearer ownership and lower ambiguity, not merely for naming purity.

View file

@ -0,0 +1,64 @@
# ADR-0002: Wave 1 `rail-kubernetes` Boundary
Date: 2026-07-25
Status: Accepted
## Context
Railiance wants `rail-*` repos to represent workload execution contracts rather
than abstract naming ideas.
Today, the concrete Kubernetes workload contract already exists, but it is
embedded in `railiance-cluster`. That repo currently owns both:
- the S2 Kubernetes substrate
- and the generic workload lifecycle and tooling that run on top of it
That mixed ownership is the main blocker to introducing the first real rail.
## Decision
Railiance will treat `rail-kubernetes` as the wave-1 base rail.
The boundary is:
- `railiance-cluster` owns the Kubernetes substrate and its prerequisites
- `rail-kubernetes` owns the generic workload-on-Kubernetes execution contract
Workload-specific helper flows currently living in `railiance-cluster` are
temporary exceptions and must be rehomed rather than carried forward as part of
the generic rail.
## Consequences
### Positive
- The first real rail gains a concrete ownership boundary.
- `railiance-cluster` can return to a clean S2 substrate identity.
- Future rails such as `rail-knative` get a stable base boundary to extend from.
- `rapp-*` repos gain a clearer execution-contract home for Kubernetes-managed
workloads.
### Required Follow-On Work
- Create the detailed `rail-kubernetes` boundary contract and migration map.
- Split generic lifecycle docs, schema, examples, and Stage 1-3 tooling out of
`railiance-cluster`.
- Leave a compatibility path so current users of the cluster repo are not
broken during the migration.
- Rehome workload-specific helpers that do not belong in either boundary.
### Constraints
- `rail-kubernetes` must not take ownership of cluster bootstrap, operators, or
kubeconfig management.
- `railiance-cluster` must not continue as the owner of generic workload
promotion semantics after the split.
- `rail-knative` should follow this cleanup, not bypass it.
## Notes
This ADR does not require all current files to move immediately.
It requires the ownership line to be explicit now, so practical repo separation
can proceed without ambiguity.

View file

@ -0,0 +1,57 @@
# ADR-0003: First-Wave `rapp-*` Selection
Date: 2026-07-25
Status: Accepted
## Context
Railiance wants `rapp-*` repos to represent managed workload packages rather
than new ownership layers.
The current workload surfaces already suggest several candidates:
- OpenBao in `railiance-platform`
- the forge workload in `railiance-forge`
- multiple S5 workloads in `railiance-apps`
But they are not equally ready for first extraction.
## Decision
The first-wave `rapp-*` order is:
1. `rapp-openbao`
2. `rapp-vergabe-teilnahme`
3. later `rapp-forgejo` after the forge runtime target stabilizes
The forge workload is explicitly deferred from the first wave because current
Gitea operation and future Forgejo direction are both active realities.
## Consequences
### Positive
- The first `rapp-*` extraction proves the third-party platform-service wrapper
model.
- The second proves the user-facing self-built app wrapper model.
- The deferred forge wrapper avoids immediate rename churn and packaging
ambiguity.
### Required Follow-On Work
- Write repo-local extraction work for `rapp-openbao`.
- Write repo-local extraction work for `rapp-vergabe-teilnahme`.
- Reassess the forge wrapper when the production package target is no longer
split between current Gitea and future Forgejo.
### Constraints
- `rapp-*` repos must stay packaging-focused and must not become shadow
ownership repos.
- Shared S3 policy stays in `railiance-platform`.
- Shared S5 release patterns stay in `railiance-apps`.
## Notes
This ADR chooses sequence, not a mandatory destination for every workload in the
ecosystem.

View file

@ -0,0 +1,61 @@
# ADR-0004: First-Wave `reef-*` Rollout
Date: 2026-07-25
Status: Accepted
## Context
Railiance now has a reef model, but it needs a concrete first rollout.
The current substrate reality is not uniform:
- Railiance01 is the clearest new-workload home
- CoulombCore is still active but transitional
- the workstation role is operator edge compute rather than server substrate
At the same time, S1 ownership is ambiguous because `railiance-hosts` and
`railiance-infra` duplicate each other.
## Decision
The first-wave reef rollout is:
1. `reef-railiance01`
2. `reef-coulombcore`
3. `reef-ops-workstations`
`railiance-infra` is the canonical S1 ownership repo going forward.
`railiance-hosts` is treated as predecessor or duplicate state to be retired,
frozen, or reduced later rather than as a second canonical S1 architecture home.
## Consequences
### Positive
- Railiance gets a primary home-reef seed without waiting for a multi-node
future.
- Transitional CoulombCore reality is acknowledged without being treated as the
long-term preferred production pattern.
- Operator edge compute is modeled without defaulting to one repo per machine.
- Reef planning now rests on one canonical S1 ownership line.
### Required Follow-On Work
- Create repo-local rollout work for the first reef repos.
- Decide whether Railiance01 later remains a singleton reef or becomes part of
a grouped home reef.
- Plan the `railiance-hosts` cleanup direction relative to `railiance-infra`.
### Constraints
- Multi-rail reefs are acceptable early, especially on transitional substrates.
- Production-grade separation should still prefer clearer purpose and primary
rail boundaries as criticality rises.
- Transitional substrate nicknames should remain provisional until the pattern
is stable enough to canonize.
## Notes
This ADR chooses the first rollout set. It does not require that every future
substrate be modeled the same way.

View file

@ -0,0 +1,187 @@
# Fabric And State Hub Adaptation For `rail-*`, `rapp-*`, And `reef-*`
Date: 2026-07-25
## Purpose
List the minimum adaptation requirements so rails, `rapp`s, and reefs become
visible ecosystem entities rather than only naming conventions.
This is a requirements document, not an implementation plan for one repo.
## Current Gaps
The current ecosystem tooling still reflects the older repo shape.
Observed gaps:
- `railiance-fabric/registry/railiance-repos.yaml` does not yet onboard
`railiance-master` or `railiance-forge`.
- Fabric has a `kubernetes-runtime` capability type, but no first-class
vocabulary for execution rails, managed workload packages, or substrate
boundaries.
- `railiance-apps` is modeled as one aggregate S5 release surface rather than a
future set of `rapp-*` package repos.
- State Hub registration and generated repo summaries do not expose repo family
or rail/rapp/reef-specific metadata.
If left unchanged, Git will know the new taxonomy before the coordination and
graph systems do.
## Minimum Questions The Systems Must Answer
After adaptation, the systems should be able to answer at least:
- which `rail-*` repos exist?
- which rail is the default base rail?
- which `rapp-*` packages support which rails?
- which reefs host which rails?
- which reefs bind or approve which `rapp`s?
- which ownership repo remains responsible for a given rail, `rapp`, or reef?
## Minimal State Hub Requirements
State Hub does not need a second work-tracking model, but it does need better
repo metadata.
### Required repo metadata
Add or derive the following repo-level concepts:
- `repo_family`: `ownership` | `rail` | `rapp` | `reef`
- `ownership_repo`: canonical owning `railiance-*` repo when the repo family is
not `ownership`
- `primary_rail`: for reefs or workloads where one rail is the declared default
- `supported_rails`: for `rapp-*` repos
- `substrate_kind`: for `reef-*` repos, such as `server`, `cluster`,
`workstation-group`, or `edge`
These fields may start in `.repo-classification.yaml` or a repo-local
companion metadata file if the classification schema should stay smaller.
### Required indexing behavior
- State Hub should index `rail-*`, `rapp-*`, and `reef-*` repos like any other
repo for workplans, tasks, and progress.
- Generated repo briefs should display repo family and any declared ownership
repo or primary rail when available.
- Repo search and inventory views should be filterable by repo family.
### Not required
- no separate workplan model for rails, `rapp`s, or reefs
- no special task state machine
- no custom approval workflow just because a repo uses one of the new prefixes
## Minimum Fabric Requirements
Fabric needs enough typed vocabulary to model the new repo families without
waiting for a perfect new object taxonomy.
### Immediate onboarding requirements
- add `railiance-master` to `registry/railiance-repos.yaml`
- add `railiance-forge` to `registry/railiance-repos.yaml`
- be ready to add future `rail-*`, `rapp-*`, and `reef-*` repos as first-class
registered repositories
### Immediate modeling requirements
Fabric should add typed representation for:
- execution rails
- managed workload packages
- substrate boundaries
The minimum viable way to do that is:
- add repo-family-aware metadata in registration and graph export
- add new `service_type` values:
- `execution-rail`
- `managed-workload-package`
- `substrate-boundary`
- add one new capability type for rails:
- `workload-execution-contract`
This keeps the first rail queryable as a provider-like ecosystem object without
forcing `rapp`s and reefs into the wrong provider/consumer semantics.
### Relation requirements
Fabric needs explicit relations for:
- `supports_rail`: `rapp` -> `rail`
- `hosts_rail`: reef -> `rail`
- `binds_rapp`: reef -> `rapp`
- `governed_by`: rail/`rapp`/reef -> ownership repo
These relations may begin as projected registry edges even if the declaration
schema evolves later.
The important part is that the graph can answer the topology questions above.
## Minimum Repo-Local Declaration Requirements
Every future repo family needs a small, obvious declaration surface.
### `rail-*`
Minimum declaration concepts:
- rail id
- owning repo
- execution architecture
- substrate prerequisites
- supported rollout modes
- compatibility notes for participating `rapp`s
### `rapp-*`
Minimum declaration concepts:
- workload package id
- upstream or source workload identity
- owning repo
- supported rails
- runtime dependencies
- rollout, smoke, and rollback contract
### `reef-*`
Minimum declaration concepts:
- substrate id
- substrate kind
- lifecycle and criticality
- hosted rails
- bound or approved `rapp`s
- primary rail, if one exists
These declarations may begin as repo-local YAML files or be projected from
existing source files. The key requirement is that they are source-controlled
and ingestible.
## Compatibility Guidance
Do not block the repo-family rollout on a perfect Fabric redesign.
Recommended compatibility-first path:
1. register the repos and family metadata
2. add the minimum new service and relation vocabulary
3. let the first `rail-*`, `rapp-*`, and `reef-*` repos publish small
declaration files
4. ingest those declarations into Fabric and State Hub projections
5. only then decide whether stronger first-class schema kinds are needed
This avoids waiting for a large graph refactor before the architecture can move.
## Outcome
The minimal adaptation target is:
- State Hub understands which repo family a repo belongs to
- Fabric can show rails, `rapp`s, and reefs as typed ecosystem entities
- the graph can answer rail/package/substrate placement questions
- new repo families are coordinated by the same workplan and progress system as
the existing Railiance repos

View file

@ -0,0 +1,200 @@
# Wave 1 `rail-kubernetes` Boundary
Date: 2026-07-25
## Purpose
Define the wave-1 extraction boundary between `railiance-cluster` and a future
`rail-kubernetes` repo.
This document exists to make `rail-kubernetes` real rather than rhetorical.
Today, `railiance-cluster` already contains the practical contract for running
managed workloads on Kubernetes:
- `docs/deployment-lifecycle.md`
- `docs/app-toml-contract.md`
- `docs/overlay-repo-pattern.md`
- `schemas/railiance-app.schema.json`
- `examples/railiance/app.toml`
- `bin/railiance`
- `tools/cmd/railiance-run`
- `tools/cmd/railiance-stage2`
- `tools/cmd/railiance-stage3`
- `tools/create_railiance_overlay_repo.sh`
That is already a rail in substance. The problem is that it currently lives
inside the S2 cluster-runtime repo.
## Decision Summary
- `rail-kubernetes` is the default base rail for wave 1.
- `railiance-cluster` remains the S2 owner of the Kubernetes substrate.
- `rail-kubernetes` owns the generic workload-on-Kubernetes execution contract.
- Workload-specific helpers currently living in `railiance-cluster` are not
part of the long-term boundary for either repo. They are migration debt that
must be rehomed.
## What `railiance-cluster` Keeps
`railiance-cluster` remains responsible for the Kubernetes substrate itself.
It keeps ownership of:
- k3s installation, upgrade, and baseline configuration
- cluster networking, ingress controllers, DNS, and certificate plumbing
- cluster operators and addons such as cert-manager, CloudNative PG operator,
ArgoCD, admission controllers, and similar cluster-scoped services
- kubeconfig management, runtime access patterns, and cluster backup/restore
posture
- cluster smoke tests that prove substrate readiness
- cluster-level runbooks for substrate recovery, upgrade, access, and failure
handling
- cluster capability declarations that tell higher layers what the substrate
actually supports
`railiance-cluster` may describe the prerequisites a rail needs from the
substrate, but it should not own the workload lifecycle semantics that run on
top of those prerequisites.
## What `rail-kubernetes` Must Own
`rail-kubernetes` owns the generic contract for Railiance-managed workloads
that run on Kubernetes.
It should own:
- the three-stage lifecycle semantics for Kubernetes-backed workloads
- the canonical `railiance/app.toml` contract for the Kubernetes rail
- the machine-readable schema and reference example for that contract
- the generic Stage 1, Stage 2, and Stage 3 CLI/tooling
- Kubernetes-specific check types, rollout modes, and rollback expectations
- the generic packaging pattern for Kubernetes-managed `rapp`s
- the generic repo scaffold for Kubernetes-targeting wrappers
- compatibility guidance for how a `rapp` declares Kubernetes namespaces,
releases, probes, ingress, routing, and rollback
- the documented compatibility path from today's overlay pattern into future
`rapp-*` repos
In short:
- `railiance-cluster` answers "is the Kubernetes substrate present and healthy?"
- `rail-kubernetes` answers "how does a Railiance-managed workload run on that
substrate?"
## What Should Not Stay In Either Boundary
Some items currently inside `railiance-cluster` are not good long-term
residents of either `railiance-cluster` or the future `rail-kubernetes`.
Examples include workload-specific helpers such as:
- `deploy-triage-robustness`
- `admin-sync-smoke`
- workload-specific runtime reconcile flows tied to `activity-core` or similar
single-workload concerns
These belong with the owning workload or ownership repo unless they are
refactored into clearly generic rail behavior.
`rail-kubernetes` must not become a second junk drawer after the split.
## File And Artifact Migration Map
| Current location in `railiance-cluster` | Target owner | Notes |
| --- | --- | --- |
| `docs/deployment-lifecycle.md` | `rail-kubernetes` | Generic workload lifecycle, no longer S2-owned |
| `docs/app-toml-contract.md` | `rail-kubernetes` | Base rail contract for Kubernetes-managed workloads |
| `schemas/railiance-app.schema.json` | `rail-kubernetes` | Versioned workload declaration schema |
| `examples/railiance/app.toml` | `rail-kubernetes` | Reference contract example |
| `docs/overlay-repo-pattern.md` | `rail-kubernetes` | Keep as compatibility doc, evolve toward `rapp-*` language |
| `tools/create_railiance_overlay_repo.sh` | `rail-kubernetes` | Keep behavior initially, then retarget toward `rapp-*` scaffolding |
| `docs/railiance-run-command.md` | `rail-kubernetes` | Stage 1 command reference |
| `docs/stage2-deploy-observe.md` | `rail-kubernetes` | Stage 2 command reference |
| `tools/cmd/railiance-run` | `rail-kubernetes` | Generic Stage 1 tooling |
| `tools/cmd/railiance-stage2` | `rail-kubernetes` | Generic Stage 2 tooling |
| `tools/cmd/railiance-stage3` | `rail-kubernetes` | Generic Stage 3 tooling |
| `bin/railiance` generic lifecycle commands | `rail-kubernetes` | `run`, `deploy`, `observe`, `promote`, `rollback`, `create-overlay` |
| `bin/railiance` substrate/bootstrap commands | `railiance-cluster` | `doctor`, `plan-host`, `cloudinit`, `backup`, `preflight`, similar substrate helpers |
| `tests/smoke_kube.sh`, cluster bootstrap tests | `railiance-cluster` | Substrate health proof |
| workload-specific reconcile helpers | rehome later | Move to owner repo or rewrite as generic rail helpers |
## The Interface Between The Two Repos
The clean split depends on a narrow interface.
`railiance-cluster` should publish a Kubernetes substrate profile that
`rail-kubernetes` can consume. At minimum, that profile should declare:
- cluster distro and supported Kubernetes version range
- ingress controller and ingress classes
- supported canary modes, such as `isolated` and optional `weighted`
- certificate management path
- default storage classes and stateful-workload constraints
- required or optional operators available to workloads
- namespace and RBAC expectations for managed workloads
- observability surfaces available for health, logs, and metrics
- approved secret-delivery patterns available on this substrate
`rail-kubernetes` should not assume a capability the substrate profile does not
declare.
This keeps the substrate owner and the rail owner separate while still letting
them compose.
## Migration-Safe Path
The split should happen in six steps.
1. Create `rail-kubernetes` with the copied contract docs, schema, examples,
and generic Stage 1-3 tooling now living in `railiance-cluster`.
2. Leave compatibility shims in `railiance-cluster` for one migration window.
The cluster repo may keep a thin `bin/railiance` wrapper that delegates the
generic lifecycle commands to `rail-kubernetes`.
3. Update the moved docs in `railiance-cluster` to become short boundary notes
that point to `rail-kubernetes` as the owning source.
4. Keep accepting the current `<app>-railiance-overlay` pattern during the
migration window, even though the long-term direction is toward `rapp-*`.
5. Rehome or delete workload-specific helpers that do not belong in either the
substrate repo or the generic Kubernetes rail.
6. Only after `rail-kubernetes` is stable should Railiance add `rail-knative`.
This path avoids breaking current users while making the new boundary real.
## Follow-On Path For `rail-knative`
`rail-knative` is the first expected follow-on rail, motivated by the need to
run `qonto-assistent`.
That follow-on rail should:
- depend on the Kubernetes substrate being described cleanly first
- reuse the top-level Railiance workload and promotion model where that remains
sensible
- own Knative-specific runtime semantics such as revisions, scale-to-zero,
traffic splitting, activator behavior, and event-driven behavior
- avoid forcing Knative-specific design choices back into the wave-1
`rail-kubernetes` boundary
The test for wave 1 is not "can Railiance describe all future rails now?"
The test is "can Railiance separate the Kubernetes base rail cleanly enough
that `rail-knative` can be added later without another taxonomy rewrite?"
## Risks To Watch
- If `railiance-cluster` keeps generic workload lifecycle ownership,
`rail-kubernetes` will be nominal only.
- If `rail-kubernetes` absorbs substrate bootstrap and operator ownership, it
stops being a rail and becomes a second cluster repo.
- If workload-specific helpers are moved unchanged into `rail-kubernetes`, the
split will preserve the current ambiguity instead of reducing it.
- If `rapp-*` migration is delayed too long, the old overlay naming and the new
workload-package model will drift apart.
## Outcome
Wave 1 should produce a base Kubernetes rail with a clean contract and a
backward-compatible migration path.
That is enough to start practical repo separation without pretending the rest
of the rail family already exists.

View file

@ -0,0 +1,169 @@
# First-Wave `rapp-*` Candidates
Date: 2026-07-25
## Purpose
Choose and order the first `rapp-*` candidates for Railiance.
`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?"
## Selection Criteria
The first-wave candidates should satisfy most of the following:
- stable workload identity
- clear upstream or source workload boundary
- clear Kubernetes package surface already visible in Git
- explicit runtime-secret and dependency handling
- deploy, verify, and recover behavior already described
- low ambiguity between packaging ownership and domain ownership
- good demonstration value for later `rapp-*` extractions
## Assessed Candidates
### 1. OpenBao from `railiance-platform`
Assessment: **choose first**
Why it fits:
- 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.
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.
### 2. Forge workload from `railiance-forge`
Assessment: **defer from first wave**
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-*`.
### 3. User-facing S5 workload from `railiance-apps`
Assessment: **choose `vergabe-teilnahme` for wave 1**
Why `vergabe-teilnahme` wins the S5 slot:
- 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`.
What should move into `rapp-vergabe-teilnahme`:
- 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
What should remain in `railiance-apps`:
- S5 ownership of generic application release patterns
- reusable onboarding and operator recipes
- cross-app S5 guardrails that should not be duplicated per workload package
Second-wave S5 note:
- `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.
Conclusion:
`rapp-vergabe-teilnahme` should be the first user-facing S5 `rapp-*`.
## First-Wave Order
The recommended order is:
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
This order is intentional.
- `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.
## 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.
## 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.

View file

@ -0,0 +1,183 @@
# First-Wave `reef-*` Rollout
Date: 2026-07-25
## Purpose
Apply the `reef-*` model to the current Railiance substrate reality and choose
the first actual reef rollout.
This document intentionally decides both:
- which reefs should exist first
- and which current repo should remain the canonical S1 ownership home while
reefs are introduced
## Current Substrate Reality
Railiance currently has three clearly different substrate realities:
### `RAILIANCE01`
- HostEurope server at `92.205.62.239`
- the most mature current home for new Kubernetes-first workloads
- already hosts Forgejo and overlapping platform services
- likely seed of a future multi-server Railiance home substrate
### `COULOMBCORE`
- HostEurope server at `92.205.130.254`
- older, mixed-purpose, still actively used
- retains current Gitea fallback and other legacy or transitional runtime
realities
- not yet fully integrated into the newer operating model
### operator workstation
- edge/operator compute, not the same kind of substrate as the servers
- hosts operator tools, local keys, bridges, kubeconfig usage, and attended
control-plane work
- likely to become a class of substrates rather than a forever-singleton machine
## Decision
The first-wave reef rollout is:
1. `reef-railiance01`
2. `reef-coulombcore`
3. `reef-ops-workstations`
Do **not** create `reef-workstation` as a singleton first-wave repo.
## Why These Three
### `reef-railiance01`
This should be the first canonical reef.
Why:
- it is already the clearest purpose-bound substrate
- it is the default home for new Kubernetes-oriented Railiance workloads
- it is the likely seed of the future Railiance home reef
- its lifecycle, access path, and workload-placement decisions are already
distinct enough to justify a dedicated reef
Primary rail stance:
- primary rail: `rail-kubernetes`
- temporary multi-rail reality is acceptable here during early growth
- later `rail-knative` may coexist on this reef if that is the most pragmatic
path for early workloads such as `qonto-assistent`
- if criticality or security pressure grows, reassess whether a broader grouped
home reef or a rail-specific separation is required
### `reef-coulombcore`
This should exist, but explicitly as a transitional reef.
Why:
- COULOMBCORE is still a real operational boundary
- it has its own access path, operational evidence, fallback responsibilities,
and recovery decisions
- it is exactly the kind of substrate that should be described honestly even if
its long-term role is not yet clean
Interpretation:
- treat it as a mixed-purpose, legacy, or transition reef
- allow multi-rail and compatibility realities here without pretending they are
the preferred long-term production pattern
- use the reef to make drain, cleanup, fallback, and migration decisions visible
Do not force a permanent taxonomy label such as "associate", "sidecar", or
"comet" yet. Those labels may become useful later, but the operational pattern
is not stable enough to canonize.
### `reef-ops-workstations`
Use a grouped reef for operator workstations.
Why:
- the workstation role is clearly a different substrate class from the servers
- the machine count is likely to grow or vary over time
- one repo per laptop would create exactly the duplication the reef model is
supposed to prevent
Interpretation:
- treat current workstation reality as the first member of an operator/edge
compute reef class
- keep machine-specific details inside the reef topology, not in separate repos
## Singleton Versus Grouped Rule Applied
Applying the reef rules to the current hosts yields:
- `RAILIANCE01`: singleton reef now, because the machine itself is the current
durable substrate boundary
- `COULOMBCORE`: singleton reef now, because it remains an independent
operational and fallback boundary
- workstation: grouped reef, because the substrate concept is "operator edge
compute" rather than one permanently special laptop
If Railiance01 later becomes one node in a clearly unified multi-node home
substrate with shared lifecycle and placement policy, reassess whether the
right target becomes a grouped reef such as `reef-railiance-home`.
Until then, `reef-railiance01` is the cleaner decision.
## `railiance-hosts` Versus `railiance-infra`
Current reality:
- `railiance-hosts` and `railiance-infra` are functionally duplicate S1 repos
- both describe the same S1 provisioning and baseline responsibility
- both contain the same authoritative-looking server inventory path
- Fabric onboarding already uses `railiance-infra`
Decision:
- `railiance-infra` is the canonical S1 ownership repo going forward
- `railiance-hosts` should be treated as a predecessor or migration duplicate,
not as the long-term authority for new architecture work
What this means:
- new framework architecture should anchor on `railiance-infra`
- reef introduction should not preserve the `hosts` naming line as a second S1
authority
- later cleanup should either retire `railiance-hosts` or reduce it to an
explicit compatibility/archive role
## Practical Rollout Sequence
The reef rollout should happen in this order:
1. create `reef-railiance01` as the first canonical home reef seed
2. create `reef-coulombcore` as the transitional legacy/fallback reef
3. create `reef-ops-workstations` as the grouped operator-edge reef
4. document `railiance-infra` as canonical S1 and plan the `railiance-hosts`
retirement or freeze direction
## Risks To Watch
- If `reef-coulombcore` is described as if it were the preferred long-term
production substrate, the reef model will normalize transitional mess instead
of making it visible.
- If `reef-workstation` is created first, the framework will drift toward
one-repo-per-machine duplication.
- If `railiance-hosts` and `railiance-infra` remain equally canonical, reef
ownership will rest on an unstable S1 base.
## Outcome
Railiance now has a concrete first reef rollout:
- `reef-railiance01` as the primary home-reef seed
- `reef-coulombcore` as the transitional legacy/fallback reef
- `reef-ops-workstations` as the grouped operator-edge reef
That is enough to move from reef theory into practical repo planning.

View file

@ -0,0 +1,262 @@
# Reef Substrate Model
Date: 2026-07-25
## Definition
A `reef-*` repo is the conceptual home for one durable Railiance substrate
boundary.
A reef is the place where:
- infrastructure becomes a named operational reality,
- rails are installed or made available,
- managed workloads are bound,
- and operators interact with a concrete environment.
More concretely, a reef represents **compute resources organized for a defined
purpose**.
The substrate may be:
- a single named server,
- a cluster,
- a workstation,
- an edge site,
- a lab substrate,
- or a small fleet treated as one unit.
The important point is not the shape of the hardware. The important point is
that the compute resources form one recognizable operational boundary.
## Why `reef-*` Instead Of `host-*`
`host-*` is too narrow for the intended concept.
Railiance substrates are not always just hosts. They may also be:
- operator workstations,
- Kubernetes substrates,
- serverless-capable execution surfaces,
- grouped node fleets,
- or mixed environments with both machines and control surfaces.
`reef-*` is useful because it names the substrate reality that rails attach to,
not merely the hardware object underneath it.
## Core Responsibility Of A Reef
A reef repo should answer:
- What is this substrate called?
- What components belong to it?
- What access paths and operator assumptions apply?
- Which rails exist here?
- Which `rapp`s are allowed or deployed here?
- Which overlays, exceptions, and evidence are specific to this substrate?
It should also make the substrate purpose explicit, so the existence of the
reef is justified by its role rather than by a hostname alone.
It is therefore an environment or substrate boundary repo, not a generic
infrastructure logic repo.
## What A Reef Owns
A reef repo may own:
- substrate identity and metadata
- topology and membership description
- rail bindings for this substrate
- `rapp` bindings for this substrate
- substrate-specific overlays and values
- substrate-specific runbooks
- substrate-specific evidence and readiness notes
- access-path descriptions such as bridges, kubeconfig routes, or workstation
assumptions
## What A Reef Does Not Own
A reef repo should not become the place for:
- generic OS provisioning logic that belongs in `railiance-infra`
- generic cluster runtime logic that belongs in `railiance-cluster`
- generic platform-service logic that belongs in `railiance-platform`
- generic workload packaging that belongs in a `rapp-*` repo
- generic rail semantics that belong in a `rail-*` repo
Reefs compose those concerns into a concrete substrate. They do not replace
their owning repos.
## Granularity Rules
The main risk with reefs is repo explosion through near-duplicate per-machine
repos. The default rules below are intended to prevent that.
### Rule 1: One Reef Per Substrate Boundary, Not Per Node By Default
If multiple machines form one operational substrate with the same lifecycle,
access path, and overlays, prefer one reef.
Example:
- Prefer `reef-ops-workstations` over one repo per laptop if they are managed as
one operator substrate class.
### Rule 2: A Single Machine Gets Its Own Reef Only When It Is The Boundary
A single named machine can justify its own reef when it is itself a durable
substrate boundary.
This is reasonable when the machine has:
- unique operational identity,
- unique overlays or access paths,
- unique binding decisions,
- or independent migration and recovery decisions.
### Rule 3: Group Fungible Fleets
Do not create one reef per fungible worker, node, or ephemeral instance.
Represent those inside one reef's topology instead.
### Rule 4: Prefer Stable Operational Names
A reef name should follow the durable substrate identity used by operators.
Good examples:
- `reef-coulombcore`
- `reef-railiance01`
- `reef-workstation`
- `reef-ops-workstations`
Avoid names tied only to transient VM ids, cloud instance ids, or incidental
hardware details.
### Rule 5: Allow Multi-Rail Reefs Early, Prefer Clearer Separation Later
It is acceptable for one reef to host multiple rails when the substrate is
experimental, preproduction, prototyping, or otherwise intentionally mixed.
For production-grade, enterprise-grade, or premium-security situations, the
better default is clearer separation by substrate purpose and a more explicit
primary rail per reef unless there is a reviewed reason to mix rails.
This is guidance, not a hard prohibition. The point is to keep the substrate
model operationally legible as criticality increases.
### Rule 6: Do Not Canonize Transitional Substrate Labels Too Early
Railiance may observe loosely planned or historically accumulated compute
resources that are still in use but do not yet fit a clean substrate class.
Those realities should be described plainly in architecture notes or reef-local
documents, but the taxonomy should avoid locking in catchy names before the
operational pattern is mature enough to deserve a stable term.
## Guidance For Current Railiance Substrates
### `COULOMBCORE`
`reef-coulombcore` is reasonable if COULOMBCORE remains a durable singleton
substrate with its own:
- access paths,
- operational evidence,
- rail availability,
- and workload binding decisions.
It may also serve as the temporary home for older or transitional workloads
that have not yet been integrated into newer operating patterns.
What should not be decided too early is a permanent taxonomy term for that
kind of substrate. Terms such as "associate", "sidecar", or "comet" may be
useful exploration language, but they should stay provisional until the pattern
repeats and earns a stable place in the framework vocabulary.
### `RAILIANCE01`
`reef-railiance01` is reasonable if Railiance01 is separately managed, migrated,
or recovered, rather than being just another fungible node in a larger
substrate.
At the current maturity level, it is acceptable for `reef-railiance01` to host
`rail-kubernetes` and later also `rail-knative` if that is the most pragmatic
way to support early workloads.
If that substrate becomes production-critical or security-sensitive, reassess
whether a clearer reef separation is warranted.
### `WORKSTATION`
If there is effectively one operator workstation with unique responsibility,
`reef-workstation` is acceptable.
If Railiance expects multiple equivalent operator machines, prefer a grouped
reef such as `reef-ops-workstations` and model individual machines inside that
repo instead of multiplying repos.
This class of reef is best understood as edge or operator compute, not as part
of the same substrate category as a home server reef.
## Suggested Reef Repo Layout
The exact layout can evolve, but a reef repo should have an obvious substrate
home structure.
```text
reef-<substrate-id>/
README.md
INTENT.md
SCOPE.md
substrate/
identity.yaml
topology.yaml
bindings/
rails.yaml
rapps.yaml
overlays/
runbooks/
evidence/
```
Suggested file responsibilities:
- `substrate/identity.yaml`: substrate id, type, owner, lifecycle, criticality
- `substrate/topology.yaml`: members, providers, network zones, access surfaces
- `bindings/rails.yaml`: rails available on this substrate
- `bindings/rapps.yaml`: `rapp`s bound or approved for this substrate
- `overlays/`: substrate-specific values or adapter overlays
- `runbooks/`: substrate-local operations and recovery
- `evidence/`: substrate readiness, migration, or recovery evidence
## Relationship To Railiance Fabric
Reefs should become first-class graph objects in `railiance-fabric`.
At minimum, Fabric should eventually be able to answer:
- Which reefs provide `rail-kubernetes`?
- Which reefs bind `rapp-openbao`?
- Which reefs are production-critical?
- Which rails are available on `reef-coulombcore`?
- Which `rapp`s depend on a given reef?
Until Fabric gains first-class reef vocabulary, reef repos should still use
clear file-backed declarations so later ingestion is straightforward.
## Recommended Decision
Adopt `reef-*` as the substrate-boundary prefix for Railiance.
Use it carefully:
- yes for real substrate boundaries,
- no for arbitrary one-repo-per-machine duplication,
- and yes for grouped substrate classes when that better matches operational
reality.
Treat a reef as purpose-bound compute first. The exact machine count is
secondary.

254
docs/repository-axes.md Normal file
View file

@ -0,0 +1,254 @@
# Repository Axes In Railiance
Date: 2026-07-25
## Purpose
Railiance needs more than one way to classify repositories.
The existing stack already expresses ownership and responsibility well, but it
does not yet cleanly express:
- how workloads are executed on different operations architectures,
- how a managed workload package is represented as its own repo,
- and how a concrete substrate or deployment reality is represented.
This document defines the canonical repository axes for Railiance.
## Current Architectural Stance
The taxonomy is intentionally broader than the current implementation wave.
For the current phase of Railiance:
- `rail-kubernetes` is the default and first-class base rail for platform
services and managed applications.
- Additional rails should be introduced only when a concrete workload has a
sound reason to run better on a different execution architecture.
- `rail-knative` is the first expected follow-on rail, driven by the need to
run `qonto-assistent`, but it should follow the `rail-kubernetes` boundary
cleanup rather than bypass it.
This means the repo model is intentionally ahead of the repo count.
## The Four Repo Families
| Prefix | Axis | Unit | Primary question answered |
| --- | --- | --- | --- |
| `railiance-*` | ownership and responsibility | one architectural responsibility area | who owns this capability or layer? |
| `rail-*` | execution contract | one workload execution architecture | how does a workload run here? |
| `rapp-*` | managed workload package | one Railiance-managed workload | what exactly is being packaged and operated? |
| `reef-*` | substrate boundary | one durable substrate reality | where does this run and what is bound there? |
These families are complementary, not competing.
## 1. `railiance-*`: Responsibility Repos
`railiance-*` repos are the long-lived architectural homes for major
responsibility areas.
Examples:
- `railiance-infra`
- `railiance-cluster`
- `railiance-platform`
- `railiance-enablement`
- `railiance-apps`
- `railiance-forge`
- `railiance-fabric`
- `railiance-master`
They answer questions such as:
- Which layer owns this concern?
- Where do the shared rules, runbooks, and contracts live?
- Which team or operator domain is responsible for correctness?
They should not be multiplied per host, per workload, or per execution mode.
## 2. `rail-*`: Execution-Contract Repos
`rail-*` repos define how Railiance-managed workloads run on a specific
operations architecture.
Examples:
- `rail-kubernetes`
- `rail-knative`
- `rail-keda`
- `rail-fission`
- `rail-nuclio`
A rail owns the execution semantics for workloads on that architecture:
- packaging expectations
- deployment adapters
- autoscaling and traffic behavior
- health and observability contract
- promotion and rollback behavior
- rail-specific templates and compatibility rules
A rail is not the workload itself and not the substrate it runs on.
In the current Railiance model, `rail-kubernetes` is the default base rail.
Other rails should be introduced only when their runtime semantics justify a
distinct lifecycle, contract, or operator model.
That makes the first question for a new rail:
- does this workload truly need a different rail,
- or does it only need an adapter or profile on the current Kubernetes path?
## 3. `rapp-*`: Managed Workload Package Repos
`rapp-*` repos represent Railiance-managed workloads as first-class packages.
Examples:
- `rapp-openbao`
- `rapp-forgejo`
- `rapp-vergabe-teilnahme`
A `rapp` may wrap:
- an upstream third-party product,
- an internal service,
- a user-facing application,
- or a platform service operated as a workload.
Its purpose is to provide the scaffolding needed to run that workload as a
fully managed component in the Railiance and Net Kingdom operating context,
including the Helix Forge software-factory environment that produces and runs
parts of that ecosystem.
A `rapp` owns:
- the Railiance packaging of the workload
- rail compatibility declarations
- workload-specific health checks and smoke checks
- workload-specific rollout and rollback expectations
- secret references, dependency declarations, and data handoff expectations
A `rapp` does not replace the responsibility repo that owns the broader domain.
It is explicitly about managed wrapping, not ownership.
For example:
- `railiance-platform` may own why OpenBao exists as an S3 platform capability
- `rapp-openbao` may own how OpenBao is packaged and operated as a managed workload
## 4. `reef-*`: Substrate-Boundary Repos
`reef-*` repos represent concrete substrate realities where rails and `rapp`s
are bound.
Examples:
- `reef-coulombcore`
- `reef-railiance01`
- `reef-workstation`
- `reef-ops-workstations`
A reef answers questions such as:
- What is this substrate?
- Which hosts, clusters, namespaces, or operator machines compose it?
- Which rails are installed or allowed here?
- Which `rapp`s are bound to it?
- Which access paths, overlays, and local runbooks apply here?
A reef does not replace `railiance-infra`, `railiance-cluster`, or
`railiance-platform`. It composes them into a named operational reality.
In practice, a reef represents compute resources organized for a defined
purpose.
One reef may host multiple rails in early-stage, experimental, prototyping, or
preproduction situations. For production-grade or premium-security use, the
better default is clearer substrate separation and an explicit primary rail per
reef unless a mixed-rail design is deliberately justified.
## How The Axes Compose
The same deployed reality may appear across all four axes for different reasons.
Example: OpenBao on COULOMBCORE
- `railiance-platform` owns the platform-service responsibility and policy
- `rail-kubernetes` defines the Kubernetes execution contract
- `rapp-openbao` defines the managed workload package
- `reef-coulombcore` records that this substrate offers that rail and binds that
`rapp`
This separation reduces confusion between:
- ownership
- execution mode
- workload identity
- deployment location
## Creation Rules
Use the following default rules.
### Create or extend a `railiance-*` repo when:
- the concern is a stable responsibility area,
- multiple workloads share the same owner and policy boundary,
- or the repo must remain the canonical home for a layer or cross-cutting
capability.
### Create a `rail-*` repo when:
- a workload execution architecture has distinct runtime semantics,
- workloads need architecture-specific templates or promotion behavior,
- or the current `railiance-cluster` contract would become too Kubernetes-only.
Default bias:
- first stabilize `rail-kubernetes`
- then add another rail only when a concrete workload needs it
### Create a `rapp-*` repo when:
- a workload should be managed as a first-class package,
- the workload has its own compatibility, rollout, or recovery contract,
- or wrapping logic should be kept separate from both the upstream source and
the generic ownership repo.
Do not create a `rapp` merely to duplicate a responsibility home that already
belongs in a `railiance-*` repo.
### Create a `reef-*` repo when:
- there is a durable substrate boundary with its own lifecycle,
- rails and `rapp`s need to be bound to a named operational reality,
- substrate-specific overlays or evidence must be tracked,
- or operators need a source-controlled home for that environment.
Do not create a reef only because a single machine happens to exist. The
substrate needs a durable purpose.
## Migration Direction From The Current Repo Set
The current Railiance repos already provide the ownership axis.
The likely next architecture moves are:
1. Move Kubernetes-specific workload execution contracts out of
`railiance-cluster` into `rail-kubernetes`.
2. Split first-class workload wrappers out of `railiance-apps`,
`railiance-platform`, and `railiance-forge` into `rapp-*` repos where the
workload deserves an independent lifecycle.
3. Introduce `reef-*` repos only for real substrate boundaries, not as a
default per-machine pattern.
4. Extend `railiance-fabric` so rails, `rapp`s, and reefs become first-class
graph objects rather than implicit naming conventions.
## Open Discipline
Railiance should resist naming every observed pattern too early.
This especially applies to loosely associated or transitional compute
resources. Terms for such substrates should stay descriptive until there is a
stable operational pattern worth canonizing in the taxonomy.