Add rapp declaration schema with composition block (WP-0021 T02, T03)
schemas/rapp.schema.json defines one normative shape for the rollout, smoke and rollback contracts in place of the three mutually unreadable variants found across the live rapps, promotes contract_version, readiness_state, data_classification and criticality to required, and forbids the rapp- prefix on workload_identity.name. composition replaces the flat members list per amendment f88f938d: purpose, member_repos with deployables, and pinned upstream_components. Repos are many:many with rapps; deployables are 1:1, which is what makes the T06 coverage check well-formed. ownership_repo left permissive pending an architecture-owner call; the tighter alternative is written up in schemas/README.md. Validated against all three live declarations: openbao 10 errors, postgres 10, qonto 4 — precisely the reported drift and nothing else. Also found: three further rapp-* repos (secrets-engine, tenant-engine, user-engine) carry no declarations at all, which the routed survey missed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
8fc92bd7d2
commit
28cbba1025
3 changed files with 525 additions and 2 deletions
100
schemas/README.md
Normal file
100
schemas/README.md
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
# Railiance family declaration schemas
|
||||
|
||||
Normative schemas for the repo-family declaration files. `docs/repo-family-bootstrap-contract.md`
|
||||
names the minimum fields; these schemas define their shapes and are the
|
||||
authority where the two disagree.
|
||||
|
||||
| Family | Declaration path | Schema |
|
||||
|---|---|---|
|
||||
| `rapp-*` | `declarations/rapp.yaml` | `rapp.schema.json` |
|
||||
| `rail-*` | `declarations/rail.yaml` | `rail.schema.json` (RAILIANCE-WP-0021-T04) |
|
||||
| `reef-*` | `declarations/reef.yaml` | `reef.schema.json` (RAILIANCE-WP-0021-T04) |
|
||||
|
||||
Written under `RAILIANCE-WP-0021` from the drift survey routed by
|
||||
`railiance-platform` under its `RAILIANCE-WP-0015` (State Hub messages
|
||||
`04c776c4`, `f88f938d`).
|
||||
|
||||
## The two cardinalities
|
||||
|
||||
These are the load-bearing rules. Everything the validator can usefully check
|
||||
follows from keeping them distinct.
|
||||
|
||||
- **Repos to rapps is many-to-many.** A repo may contribute to more than one
|
||||
rapp — a shared library, or a service that is a member of one bundle and a
|
||||
dependency of another.
|
||||
- **Deployables to rapps is one-to-one.** Every running deployable has exactly
|
||||
one rapp that owns its rollout.
|
||||
|
||||
The second is what makes the coverage question well-formed: *does every live
|
||||
deployable belong to exactly one rapp?* That single check catches stale reef
|
||||
bindings, unpackaged live workloads, and the workload-count gap at once. It is
|
||||
what turns this schema from a one-shot lint into a standing control loop.
|
||||
|
||||
Rapp bounded context is therefore its own dimension, derived neither from
|
||||
Forgejo organizations nor from State Hub domains. A repo lives in exactly one
|
||||
Forgejo org, so `org:repo` is one-to-many, and a many-to-many grouping cannot
|
||||
be derived from a one-to-many one. Domains fail in both directions. See
|
||||
`docs/adr/ADR-0007` (T07) and decision `d07ee5f9`.
|
||||
|
||||
## Normative choices, and what they cost
|
||||
|
||||
The three live rapp declarations expressed their rollout, smoke and rollback
|
||||
contracts three mutually unreadable ways. The schema picks one shape. Where it
|
||||
picks, it says so and it says who pays.
|
||||
|
||||
**`default_mode` is kept** — all three declarations already carried it. No cost.
|
||||
|
||||
**`supported_commands` becomes `commands`** in all three contracts. Mechanical
|
||||
rename for `rapp-openbao` and `rapp-postgres`.
|
||||
|
||||
**`smoke_contract.required` is required, and `commands` is optional.** Taken
|
||||
from `rapp-qonto`. This is the one migration with real cost: the platform rapps
|
||||
declare only commands, so their owners must name the outcomes those commands
|
||||
establish. That cost is the point. A command list records what was run; a
|
||||
required list records what must be true. Only the second can be checked by
|
||||
anything other than the person who ran it.
|
||||
|
||||
**`rollback_contract.order` is required.** Taken from `rapp-qonto`. Recoverable
|
||||
from the command sequences the platform rapps already document, so the cost is
|
||||
low. `direct_kubernetes_fallback` generalizes to `fallback`.
|
||||
|
||||
**`workload_identity.name` is the workload, never the repo**, and the schema
|
||||
forbids the `rapp-` prefix on it outright. `rapp-qonto` currently sets it to
|
||||
`rapp-qonto`; the correct value is `qonto`.
|
||||
|
||||
**`contract_version`, `readiness_state`, `data_classification` and
|
||||
`criticality` are required.** All four exist only in `rapp-qonto` today. The
|
||||
first two are promoted because the rail family has carried them consistently in
|
||||
both rails and has not drifted — that contrast is the whole argument for
|
||||
schema. The second two are promoted because a package whose classification and
|
||||
criticality are unstated cannot be admitted to a reef on evidence.
|
||||
|
||||
**`consumer_contract` is schema-defined but optional.** Only `rapp-postgres`
|
||||
provisions isolated units to other services. Requiring it everywhere would be
|
||||
false precision.
|
||||
|
||||
## Open question: what may `ownership_repo` name?
|
||||
|
||||
Currently `rapp-openbao` and `rapp-postgres` name `railiance-platform`, a layer
|
||||
repo, and `rapp-qonto` names `qonto-assistant`, an application repo.
|
||||
|
||||
The schema admits **both**, requiring only that there be exactly one and that
|
||||
it not be the rapp repo itself. This is deliberately the permissive reading,
|
||||
taken so the schema does not silently invalidate two of three live declarations
|
||||
on a question the survey cannot settle.
|
||||
|
||||
The tighter alternative is that `ownership_repo` must name the repo whose team
|
||||
is accountable for the workload in production, which would likely disqualify a
|
||||
layer repo that owns dozens of unrelated workloads. That is a modelling call
|
||||
about where accountability sits, not a lint, and it belongs to the architecture
|
||||
owner. Until it is made, treat the permissive rule as provisional.
|
||||
|
||||
## Validating
|
||||
|
||||
The validator lands under `tools/` in `RAILIANCE-WP-0021-T05`. Until then these
|
||||
schemas are normative but unenforced — which is precisely the condition that
|
||||
produced the drift, so T05 should not lag T02/T03 by long.
|
||||
|
||||
Two constraints are validator-only, because JSON Schema cannot express them:
|
||||
`primary_rail` must appear in `supported_rails`, and reef `bound_rapps` must be
|
||||
derivable from the rapp declarations rather than hand-listed.
|
||||
Loading…
Add table
Add a link
Reference in a new issue