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:
parent
d3b3512a60
commit
3cc0dc31d6
20 changed files with 1509 additions and 187 deletions
|
|
@ -7,8 +7,8 @@ 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) |
|
||||
| `rail-*` | `declarations/rail.yaml` | `rail.schema.json` |
|
||||
| `reef-*` | `declarations/reef.yaml` | `reef.schema.json` |
|
||||
|
||||
Written under `RAILIANCE-WP-0021` from the drift survey routed by
|
||||
`railiance-platform` under its `RAILIANCE-WP-0015` (State Hub messages
|
||||
|
|
@ -34,7 +34,7 @@ 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`.
|
||||
`docs/adr/ADR-0007-rapp-declaration-contract.md` and decision `d07ee5f9`.
|
||||
|
||||
## Normative choices, and what they cost
|
||||
|
||||
|
|
@ -89,12 +89,97 @@ 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
|
||||
## Validator-only constraints
|
||||
|
||||
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.
|
||||
JSON Schema cannot express these; `tools/validate-family-declarations.py` does:
|
||||
|
||||
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.
|
||||
- `primary_rail` must appear in `supported_rails` (rapp) or `hosted_rails` (reef)
|
||||
- reef `bound_rapps`, if present, must match the projection of `rapp.bound_reefs`
|
||||
- a rapp `ownership_repo` must not be the rapp repo itself
|
||||
- declared member repos, named rails, and named reefs must resolve on disk
|
||||
- a deployable name may belong to at most one rapp
|
||||
|
||||
## Rail schema (T04)
|
||||
|
||||
`rail.schema.json` codifies the two live rails. It does not tighten the family
|
||||
beyond current practice.
|
||||
|
||||
Required on every rail: `kind`, `rail_id`, `repo`, `ownership_repo`,
|
||||
`contract_version`, `composition_kind`, `execution_architecture`,
|
||||
`readiness_state`, `required_substrate_capabilities`, `supported_rollout_modes`.
|
||||
|
||||
`composition_kind: derived` additionally requires `base_rail`,
|
||||
`base_rail_contract`, `inherited_semantics`, `overridden_semantics`, and
|
||||
`compatibility_constraints`. A `base` rail must not carry those fields.
|
||||
|
||||
`required_substrate_capabilities` is the live name. The bootstrap contract's
|
||||
older `substrate_prerequisites` label is retired; do not reintroduce it.
|
||||
|
||||
Rail `readiness_state` uses the composition-contract vocabulary (`declared`,
|
||||
`installed`, `verified`, `production-approved`, `deprecated`). That is
|
||||
deliberately not the rapp vocabulary and not the reef `lifecycle_state`.
|
||||
|
||||
Validated 2026-08-13 against both live rails with `jsonschema` 4.10.3: both
|
||||
conform. That is the intended contrast with the rapp family.
|
||||
|
||||
## Reef schema (T04)
|
||||
|
||||
`reef.schema.json` codifies the live `reef-railiance` declaration, with one
|
||||
normative change: `bound_rapps` is no longer a hand-maintained required field.
|
||||
|
||||
Required on every reef: `kind`, `reef_id`, `repo`, `ownership_repo`,
|
||||
`substrate_kind`, `lifecycle_state`, `criticality`, `primary_rail`,
|
||||
`hosted_rails`, `current_members`.
|
||||
|
||||
`bound_rapps` is optional. Its source of truth is `rapp.bound_reefs`. The
|
||||
validator inverts that field. If a reef still lists `bound_rapps`, the list
|
||||
must match the projection exactly.
|
||||
|
||||
**Migration for `reef-railiance`.** The current list is `[rapp-qonto]`. That
|
||||
is already stale: `rapp-openbao` and `rapp-postgres` are live on Railiance01.
|
||||
Until those three declarations name `reef-railiance` in `bound_reefs`, the
|
||||
derived projection is empty and a hand-list of anything fails. The owning
|
||||
repo should delete `bound_rapps` now, or replace it with the derived set once
|
||||
the rapps name the reef. Either is a one-line change; leaving the stale list
|
||||
is the failure mode this check exists to catch.
|
||||
|
||||
`rapp.bound_reefs` was added as a required field in the same task. An empty
|
||||
list is legal and means the package is declared but not yet placed.
|
||||
|
||||
Validated 2026-08-13 against the live reef: it conforms as a document. The
|
||||
`bound_rapps` value does not survive the derivation check, which is the
|
||||
intended result.
|
||||
|
||||
## Runtime dependencies name capabilities, not resources
|
||||
|
||||
`runtime_dependencies` is a list of capability names (`s3-backup-target`,
|
||||
`openbao-database-secrets-engine`). The schema does not, and must not, say
|
||||
who provisions the thing that satisfies a name.
|
||||
|
||||
The postgres backup object store is the worked example. `rapp-postgres`
|
||||
declares `s3-backup-target` as a consumed capability. The bucket is a
|
||||
`resource-control` resource (`RESOURCE-WP-0002`). The credential is
|
||||
`railiance-platform` OpenBao custody (`Secret platform-pg-backup-s3`).
|
||||
Purchase itself is the escalated human decision `9c21c0e0`. Until
|
||||
`resource-control` hands an endpoint to `railiance-platform`,
|
||||
`make postgres-backup-deploy` stays fail-closed on purpose. That is not a
|
||||
hole in `rapp-postgres` ownership and not a hole in this schema.
|
||||
|
||||
## Running the validator
|
||||
|
||||
```bash
|
||||
tools/validate-family-declarations.py
|
||||
tools/validate-family-declarations.py --root ..
|
||||
tools/validate-family-declarations.py --inventory path/to/live-deployables.json
|
||||
tools/validate-family-declarations.py --self-test
|
||||
```
|
||||
|
||||
`--inventory` is the T06 coverage check. This repo does not query a cluster.
|
||||
The file is produced by an implementation repo and must be a JSON mapping
|
||||
with a `deployables` list of `{name, namespace?, kind?}` (or bare name
|
||||
strings). Live names that no rapp claims are reported as wave-2 worklist
|
||||
items, not suppressed.
|
||||
|
||||
The validator is `tools/validate-family-declarations.py` (RAILIANCE-WP-0021-T05).
|
||||
It is runnable standalone now. Calling it from `fix-consistency` waits on
|
||||
`the-custodian` admitting the family prefixes; that sequencing is not ours.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue