Open RAILIANCE-WP-0021 for the rapp declaration schema
railiance-platform surveyed the four-axis model against the live cluster and all six family repos and routed the findings here (messages 04c776c4 and f88f938d): rapp.yaml has no schema and has drifted three ways, reef bound_rapps is a stale hand-maintained list, and ~17 live workloads sit against 3 rapps. Takes ownership of the schema, the composition block with its two cardinalities (repos many:many with rapps, deployables 1:1), and a validator over all three family declaration files. Migration stays with the owning repos. T01 done: both messages acknowledged, ownership confirmed to railiance-platform. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
a89019eae1
commit
f3c44c7a80
1 changed files with 345 additions and 0 deletions
345
workplans/RAILIANCE-WP-0021-rapp-declaration-schema.md
Normal file
345
workplans/RAILIANCE-WP-0021-rapp-declaration-schema.md
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
---
|
||||
id: RAILIANCE-WP-0021
|
||||
type: workplan
|
||||
title: "Rapp Declaration Schema and Family Declaration Validator"
|
||||
domain: financials
|
||||
repo: railiance-master
|
||||
status: ready
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
planning_priority: high
|
||||
planning_order: 21
|
||||
created: "2026-08-11"
|
||||
updated: "2026-08-11"
|
||||
related_repos:
|
||||
- railiance-master
|
||||
- railiance-platform
|
||||
- rapp-openbao
|
||||
- rapp-postgres
|
||||
- rapp-qonto
|
||||
- rail-kubernetes
|
||||
- rail-knative
|
||||
- reef-railiance
|
||||
- the-custodian
|
||||
---
|
||||
|
||||
# RAILIANCE-WP-0021 - Rapp Declaration Schema and Family Declaration Validator
|
||||
|
||||
## Goal
|
||||
|
||||
Give the `rapp-*` family a machine-checkable declaration contract, and stand up
|
||||
a validator over all three family declaration files (`rail.yaml`, `rapp.yaml`,
|
||||
`reef.yaml`) so that architectural drift fails loudly instead of accumulating
|
||||
quietly.
|
||||
|
||||
The deliverable is not more prose. `docs/repo-family-bootstrap-contract.md`
|
||||
already names the required `rapp.yaml` fields; naming them in prose is exactly
|
||||
what failed. The deliverable is a schema plus a check that runs.
|
||||
|
||||
## Why This Exists
|
||||
|
||||
`RAILIANCE-WP-0017` through `RAILIANCE-WP-0019` established the four-axis model
|
||||
and materialized the first concrete family repos. The model held up. Its
|
||||
enforcement did not.
|
||||
|
||||
`railiance-platform` surveyed all six family repos and the live Railiance01
|
||||
cluster on 2026-08-11 under its `RAILIANCE-WP-0015` and routed the findings
|
||||
here, on the grounds that `railiance-master` owns the model and an
|
||||
implementation repo should not author it. State Hub messages
|
||||
`04c776c4-52fa-494a-9761-942123f28a6e` (proposal) and
|
||||
`f88f938d-1ebc-4ba0-91ee-9395e44a7cb3` (amendment) carry the detail.
|
||||
|
||||
Reported drift across the three live rapps:
|
||||
|
||||
- rollout, smoke, and rollback contracts are mutually unreadable —
|
||||
`rapp-openbao` and `rapp-postgres` use `supported_commands` lists,
|
||||
`rapp-qonto` uses `default_mode` / `production_gate`, a `required:` smoke
|
||||
list and an `order:` rollback list
|
||||
- `contract_version`, `readiness_state`, `data_classification` and
|
||||
`criticality` appear only in `rapp-qonto`, though both rails carry
|
||||
`contract_version` / `readiness_state` consistently
|
||||
- `consumer_contract` / `consumers` exist only in `rapp-postgres`
|
||||
- `workload_identity.name` is the workload name in two rapps and the repo name
|
||||
in the third
|
||||
- `ownership_repo` points at a layer repo twice and at an app repo once
|
||||
- `reef-railiance` `bound_rapps` lists `rapp-qonto` only, while `rapp-openbao`
|
||||
and `rapp-postgres` are both live on Railiance01 — a hand-maintained registry
|
||||
with nothing checking it
|
||||
- roughly 17 live non-system workloads in-cluster against 3 rapps
|
||||
|
||||
The `rail-*` family received a tighter contract in wave 1 and has stayed clean.
|
||||
That contrast is the argument for schema rather than for more documentation.
|
||||
|
||||
## Current Starting Point
|
||||
|
||||
- no `schemas/` directory exists in this repo
|
||||
- `docs/repo-family-bootstrap-contract.md` lists eight required `rapp.yaml`
|
||||
fields with no shapes, no types, and no cardinality rules
|
||||
- `docs/rapp-first-wave-candidates.md` still reads as though the planned first
|
||||
wave (`rapp-openbao`, `rapp-vergabe-teilnahme`, `rapp-forgejo`) happened; the
|
||||
actual population is `rapp-openbao`, `rapp-postgres`, `rapp-qonto`, the
|
||||
latter two created ad hoc from immediate need
|
||||
- `rapp-vergabe-teilnahme` was never built, so the user-facing wrapper pattern
|
||||
it existed to prove remains unproven while the platform-service pattern has
|
||||
been proven twice
|
||||
- canon does not yet admit the family prefixes, so `fix-consistency` cannot
|
||||
call a family validator until `the-custodian` lands its side
|
||||
- `railiance-platform` is holding `RAILIANCE-WP-0015-T02` (bringing
|
||||
`rapp-openbao` and `rapp-postgres` onto one shape) until this schema exists
|
||||
|
||||
## Target Outcome
|
||||
|
||||
When this workplan is complete:
|
||||
|
||||
1. `schemas/rapp.schema.json` defines every required and optional `rapp.yaml`
|
||||
field with one normative shape per contract.
|
||||
2. A `composition:` block expresses what a grouped rapp actually is: a stated
|
||||
purpose, first-party member repos, and pinned third-party components.
|
||||
3. The two cardinalities are written down and enforced separately — repos are
|
||||
many-to-many with rapps, deployables are one-to-one.
|
||||
4. A validator runs over `rail.yaml`, `rapp.yaml`, and `reef.yaml` and fails on
|
||||
drift.
|
||||
5. Reef `bound_rapps` is derived from rapp declarations rather than
|
||||
hand-listed.
|
||||
6. `docs/rapp-first-wave-candidates.md` records what was actually built versus
|
||||
planned, and carries the grouped wave-2 inventory.
|
||||
7. Downstream repos have a single shape to converge on, and know it.
|
||||
|
||||
## Boundaries
|
||||
|
||||
This workplan owns the schema, the validator, the cardinality rules, and the
|
||||
framework documents that describe them.
|
||||
|
||||
It does not migrate any rapp repo onto the new shape — that stays with each
|
||||
owning repo, coordinated through `railiance-platform` `RAILIANCE-WP-0015-T02`.
|
||||
|
||||
It does not touch canon. Admitting the family prefixes into
|
||||
`repo-classification-standard_v1.0` is `the-custodian`'s call, routed there
|
||||
separately as `cc64764a`.
|
||||
|
||||
It does not address the Forgejo organization split. All repos currently sit
|
||||
under a single `coulomb/` org and a split into stewardship orgs is a
|
||||
URL-breaking change across every remote, CI config and ArgoCD source. It is an
|
||||
independent dimension from rapp grouping and needs its own work record.
|
||||
|
||||
## Tasks
|
||||
|
||||
## T01 - Accept the routed proposal and record the ownership decision
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0021-T01
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
Done 2026-08-11. Both messages marked read; reply `a9a8109f` sent to
|
||||
`railiance-platform` accepting ownership and confirming this workplan as the
|
||||
vehicle. No decision record was created here: `d07ee5f9` already carries the
|
||||
dimension decision from the `railiance-platform` side, and duplicating it would
|
||||
create two records of one decision. The rationale lands instead in `ADR-0007`
|
||||
under T07. One question was returned to `railiance-platform` — whether they can
|
||||
emit the live deployable inventory that T06 needs, so this repo does not
|
||||
acquire a cluster dependency.
|
||||
|
||||
Read and acknowledge State Hub messages `04c776c4` and `f88f938d`, mark them
|
||||
read, and reply to `railiance-platform` confirming that `railiance-master`
|
||||
accepts ownership of the schema and that this workplan is the vehicle.
|
||||
|
||||
Record the framework decision that rapp bounded context is a grouping dimension
|
||||
in its own right, derived neither from Forgejo organizations nor from State Hub
|
||||
domains, with the cardinality argument as rationale: a repo lives in exactly
|
||||
one Forgejo org, so `org:repo` is one-to-many, while a repo may legitimately
|
||||
contribute to more than one rapp, so `rapp:repo` is many-to-many — and a
|
||||
many-to-many grouping cannot be derived from a one-to-many one. Domains fail in
|
||||
both directions. The three dimensions also change at different speeds.
|
||||
|
||||
Reference OAS P1 in `canon/standards/orthogonal-architecture_v1.0.md`: separate
|
||||
independent perspectives into orthogonal dimensions.
|
||||
|
||||
## T02 - Author schemas/rapp.schema.json
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0021-T02
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Create `schemas/` and write `rapp.schema.json` covering:
|
||||
|
||||
- the eight fields already required by the bootstrap contract: `rapp_id`,
|
||||
`workload_identity`, `ownership_repo`, `supported_rails`,
|
||||
`runtime_dependencies`, `rollout_contract`, `smoke_contract`,
|
||||
`rollback_contract`
|
||||
- `contract_version` and `readiness_state`, matching the shape the rail family
|
||||
already carries
|
||||
- `data_classification` and `criticality`, promoted from `rapp-qonto`-only to
|
||||
required
|
||||
- `consumer_contract`, promoted from `rapp-postgres`-only to optional but
|
||||
schema-defined
|
||||
|
||||
Settle the two definitional questions the survey exposed. `workload_identity.name`
|
||||
is the workload, never the repo. `ownership_repo` names the repo that owns the
|
||||
workload's lifecycle; state explicitly whether a layer repo is a legal value,
|
||||
since current declarations disagree.
|
||||
|
||||
Pick one normative shape for `rollout_contract`, `smoke_contract` and
|
||||
`rollback_contract` rather than admitting all three observed variants. Note in
|
||||
the schema which existing declaration the chosen shape most resembles, so
|
||||
migration cost is visible.
|
||||
|
||||
## T03 - Define the composition block and its cardinality rules
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0021-T03
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Supersede the flat `members:` list from the original proposal with the
|
||||
composition block from the amendment:
|
||||
|
||||
```yaml
|
||||
composition:
|
||||
purpose: <what this coherent workload does>
|
||||
member_repos: # first-party, each sharing rollout and rollback fate
|
||||
- repo: <slug>
|
||||
role: <what it contributes>
|
||||
deployables: [<names>]
|
||||
upstream_components: # third-party, pinned
|
||||
- name: <chart|image|operator>
|
||||
source: <repo/chart or registry ref>
|
||||
version: <pin>
|
||||
```
|
||||
|
||||
Encode both cardinalities. A repo may appear in the `member_repos` of more than
|
||||
one rapp. A deployable must belong to exactly one rapp — each running
|
||||
deployable has exactly one rapp owning its rollout. Keeping these distinct is
|
||||
what makes the coverage check in T06 well-defined.
|
||||
|
||||
Carry the operator decision of 2026-08-11 into the schema: rapp granularity is
|
||||
grouped-by-bounded-context, one rapp per cohesive group that deploys, versions
|
||||
and rolls back together, not one per deployable. Grouping is legitimate only
|
||||
where members share rollout and rollback fate; make that testable rather than
|
||||
advisory where possible.
|
||||
|
||||
## T04 - Schematize rail.yaml and reef.yaml, and derive bound_rapps
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0021-T04
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Write `schemas/rail.schema.json` and `schemas/reef.schema.json` from the
|
||||
minimum field sets in `docs/repo-family-bootstrap-contract.md`. The rail family
|
||||
has stayed clean, so this is largely codifying what already works; do not
|
||||
tighten it beyond current practice without cause.
|
||||
|
||||
Change `reef.yaml` `bound_rapps` from a hand-maintained list to a derived
|
||||
projection of the rapp declarations that name the reef, and record the
|
||||
migration path for `reef-railiance`, whose current list is already known stale.
|
||||
|
||||
## T05 - Build the family declaration validator
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0021-T05
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Add a validator under `tools/` that walks the family repos, locates each
|
||||
`declarations/*.yaml`, and validates it against the matching schema.
|
||||
|
||||
Checks in priority order, per the routed proposal:
|
||||
|
||||
1. every declaration conforms to its schema
|
||||
2. every declared member repo and upstream pin resolves
|
||||
3. reef `bound_rapps` is derivable from rapp declarations rather than
|
||||
hand-listed
|
||||
4. deployable coverage — deferred to T06, which needs cluster state
|
||||
|
||||
Exit non-zero on any failure and name the offending file and field. Make it
|
||||
runnable standalone now, and callable from `fix-consistency` later; do not
|
||||
block on canon admitting the prefixes, since that is `the-custodian`'s
|
||||
sequencing, not ours.
|
||||
|
||||
## T06 - Add the deployable coverage check
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0021-T06
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Extend the validator with the standing control-loop question: does every live
|
||||
deployable belong to exactly one rapp?
|
||||
|
||||
This is the check that turns the schema from a one-shot lint into an ongoing
|
||||
control loop. Per the amendment it catches all three drift findings at once —
|
||||
stale reef bindings, unpackaged live workloads, and the roughly
|
||||
17-workloads-versus-3-rapps gap.
|
||||
|
||||
Decide how live cluster state reaches the check without `railiance-master`
|
||||
acquiring a cluster dependency it should not have. Consuming an inventory
|
||||
produced by an implementation repo is preferable to querying Railiance01 from
|
||||
here.
|
||||
|
||||
Expect the first run to report a large uncovered set. That output is the wave-2
|
||||
worklist, not a failure to suppress.
|
||||
|
||||
## T07 - Update the bootstrap contract to point at the schemas
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0021-T07
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Revise `docs/repo-family-bootstrap-contract.md` so the minimum-field lists cite
|
||||
the schema files as normative rather than restating fields in prose. Prose that
|
||||
duplicates a schema will drift from it.
|
||||
|
||||
Record an ADR (next free number, `ADR-0007`) for the framework decisions this
|
||||
workplan settles: bounded rapp context as an independent dimension, the two
|
||||
cardinalities, and grouped-by-bounded-context granularity.
|
||||
|
||||
## T08 - Refresh rapp-first-wave-candidates.md
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0021-T08
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Correct the document to record what was actually built against what was
|
||||
planned: `rapp-openbao` as planned, then `rapp-postgres` and `rapp-qonto` ad
|
||||
hoc from need, and `rapp-vergabe-teilnahme` never built.
|
||||
|
||||
State the consequence plainly — the platform-service pattern is proven twice
|
||||
and the user-facing wrapper pattern is unproven — and carry the operator
|
||||
decision to build `rapp-vergabe-teilnahme` to prove the user-facing shape
|
||||
before mass extraction.
|
||||
|
||||
Add the grouped wave-2 inventory in the new composition shape. Indicative
|
||||
candidates: `rapp-netkingdom-identity` (sso, mfa, user-engine, tenant-engine,
|
||||
flex-auth), `rapp-forgejo` (forgejo, runner, registry), `rapp-coulomb-social`,
|
||||
`rapp-helix-forge`.
|
||||
|
||||
## T09 - Release the schema to downstream repos
|
||||
|
||||
```task
|
||||
id: RAILIANCE-WP-0021-T09
|
||||
status: wait
|
||||
priority: high
|
||||
```
|
||||
|
||||
Waiting on T02, T03 and T05.
|
||||
|
||||
Notify `railiance-platform` that the shape is settled and
|
||||
`RAILIANCE-WP-0015-T02` is unblocked, and notify `rapp-openbao`,
|
||||
`rapp-postgres`, `rapp-qonto` and `reef-railiance` of the migration they each
|
||||
own. Include the normative shape chosen for the rollout, smoke and rollback
|
||||
contracts and what each repo must change.
|
||||
|
||||
Migration itself belongs to the owning repos. This task ends when they have
|
||||
what they need, not when they are done.
|
||||
Loading…
Add table
Add a link
Reference in a new issue