---
id: RAILIANCE-WP-0015
type: workplan
title: "Platform rapp consistency and deployment-management contract"
domain: financials
repo: railiance-platform
status: finished
owner: codex
topic_slug: railiance
created: "2026-08-11"
updated: "2026-08-13"
related_repos:
  - railiance-master
  - the-custodian
  - reef-railiance
  - rapp-openbao
  - rapp-postgres
state_hub_workstream_id: "a14fd4d3-2e30-474f-aeea-af560c622394"
---

# RAILIANCE-WP-0015 - Platform rapp consistency and deployment-management contract

## Goal

Bring the platform-owned managed workload packages (`rapp-openbao`,
`rapp-postgres`) onto one consistent, verifiable declaration and operations
contract, and establish the S3 pattern that later platform-service rapps are cut
from.

This workplan does **not** own the four-axis repo family model. That model lives
in `railiance-master/docs/repository-axes.md` and is being promoted to custodian
canon separately. S3's job here is to be the first family member that actually
conforms, and to supply the platform-service reference shape.

## Findings that motivate this workplan

Surveyed 2026-08-11 against the live cluster and all six family repos.

The concepts are in better shape than their enforcement. The four families are
cleanly defined and `RMASTER-WP-0018`/`RMASTER-WP-0019` in `railiance-master` are both
`finished`. Nothing, however, validates a declaration file, so the model has
been drifting quietly since the first wave.

1. **The rapp population diverged from the plan of record.** Planned wave 1 was
   `rapp-openbao` → `rapp-vergabe-teilnahme` → `rapp-forgejo`. Actual is
   `rapp-openbao`, plus `rapp-postgres` and `rapp-qonto` created ad hoc from
   immediate need. `rapp-vergabe-teilnahme` was never built, so the
   *user-facing* wrapper pattern it existed to prove is still unproven while the
   platform-service pattern has been proven twice.

2. **`rapp.yaml` has no schema and has drifted three ways.** The bootstrap
   contract names eight required fields but no shapes. Result: the
   rollout/smoke/rollback contracts are mutually unreadable (`supported_commands`
   lists in openbao and postgres versus `default_mode`/`production_gate`,
   `required:` and `order:` in qonto); only qonto carries `contract_version`,
   `readiness_state`, `data_classification` and `criticality`; only postgres has
   `consumer_contract`; `workload_identity.name` is the workload name twice and
   the repo name once. `rail.yaml` by contrast is consistent — the rail family
   got a tighter contract than the rapp family.

3. **The reef binding registry is stale.** `reef-railiance` declares
   `bound_rapps: [rapp-qonto]` while `rapp-openbao` and `rapp-postgres` both run
   on Railiance01. The reef's stated purpose is recording what is bound where,
   and it missed two of three.

4. **The model is not canon.** Custodian canon has no reef/rail/rapp standard,
   and `repo-classification-standard_v1.0` does not admit the prefixes — the
   same root cause as the open C-31 failures on `RAPP-*-WP-` work-record ids.

5. **Scale gap.** ~17 live non-system workloads, 3 rapps.

## Decisions taken (2026-08-11, operator-approved)

- **Granularity: grouped by bounded context.** One rapp per cohesive service
  group that deploys, versions and rolls back together, not one per deployable.
  A grouped rapp must declare its member services explicitly — grouping is only
  legitimate where the members share a rollout and rollback fate.
- **Scope split.** S3 owns its own rapps and the platform-service pattern.
  Schema, validator and family-model changes are routed to `railiance-master`;
  canon promotion is routed to `the-custodian`. S3 does not author them.
- **Canon: promote now**, so `fix-consistency` can validate declarations.
- **Wave-1 gap: build `rapp-vergabe-teilnahme`** to prove the user-facing shape
  before further extraction. That build is `railiance-apps`/master territory,
  not S3's; this workplan only supplies the platform-service half of the pattern.

## Boundaries

This workplan may:

- change declarations and operations contracts of platform-owned rapps
  (`rapp-openbao`, `rapp-postgres` — both declare `ownership_repo: railiance-platform`)
- define the S3 platform-service rapp reference pattern
- define how credential lanes and grant catalog entries bind to a rapp
- send proposals to the repos that own the model, schema and canon

It must not:

- author the four-axis model, the `rapp.yaml` schema, or canon standards here
- edit `reef-railiance`, `rail-*`, or `railiance-master` declarations directly
- absorb platform-wide policy into a rapp (the "shadow S3 repo" failure mode
  named in `rapp-first-wave-candidates.md`)
- change any credential gate, grant delivery, or revocation semantic

## Tasks

```task
id: RAILIANCE-WP-0015-T01
status: done
priority: high
state_hub_task_id: "53f6a28f-ee10-4695-ab7f-6781b3d35c76"
```

Publish the S3 platform-service rapp pattern as `docs/rapp-platform-service-pattern.md`:
the reference `rapp.yaml` shape for a platform service, the ownership split
between rapp and S3, the grouped-rapp member declaration rule, and the
credential-lane binding. Generalize from the existing
`docs/rapp-openbao-boundary.md` and `docs/rapp-postgres-boundary.md` rather than
inventing a third boundary vocabulary.

```task
id: RAILIANCE-WP-0015-T02
status: done
priority: high
state_hub_task_id: "eada3a6f-9f4e-47bc-bfe5-2ec585f5d312"
```

Bring `rapp-openbao/declarations/rapp.yaml` and
`rapp-postgres/declarations/rapp.yaml` into a single consistent shape: add
`contract_version`, `readiness_state`, `data_classification` and `criticality`
(present in `rail.yaml` and in `rapp-qonto`, absent in both platform rapps), fix
`workload_identity.name` to be the workload rather than the repo where it drifts,
and align the rollout/smoke/rollback contract shape. Coordinate the target shape
with the `railiance-master` schema proposal (T04) before editing, so the two do
not converge on different answers.

```task
id: RAILIANCE-WP-0015-T03
status: done
priority: medium
state_hub_task_id: "493d0ab0-595c-4a14-b3d6-8c396bd7747b"
```

Correct the reef binding registry: propose to `reef-railiance` that
`bound_rapps` include `rapp-openbao` and `rapp-postgres`, with the evidence that
both are live on Railiance01. Proposal only — `reef-railiance` owns its
declaration. Ask that the binding be derived or checked rather than hand-listed,
since a hand-listed registry is what went stale.

```task
id: RAILIANCE-WP-0015-T04
status: done
priority: high
state_hub_task_id: "30cb0cb2-2ce2-4d27-8d43-c29dc32904a8"
```

Route the schema and validator proposal to `railiance-master`: a
`rapp.schema.json` covering the eight required fields plus the four consistency
fields, a validator that runs over every family declaration, the grouped-rapp
member field, and a refresh of `rapp-first-wave-candidates.md` to reflect what
was actually built and the grouped-context wave-2 inventory.

```task
id: RAILIANCE-WP-0015-T05
status: done
priority: medium
state_hub_task_id: "ca661530-5ebd-422b-854d-7b6986f0b3fe"
```

Route the canon promotion proposal to `the-custodian`: a
`railiance-repo-families` standard, declaration schemas under `canon/standards/schemas/`,
and admission of the `rail-`/`rapp-`/`reef-` prefixes into
`repo-classification-standard` and `work-record-types.yaml` — the latter closing
the open C-31 failures on multi-segment `RAPP-*-WP-` ids.

```task
id: RAILIANCE-WP-0015-T06
status: done
priority: medium
state_hub_task_id: "9ea10522-47a9-4cce-b0d8-cb6f9c7813b8"
```

Define how a rapp binds to its credential lane: the relationship between
`credential-grants/catalog.yaml` entries, CCR lanes, and a rapp's
`runtime_dependencies`/`secret_references`, so that a new rapp has one documented
way to acquire runtime secrets instead of re-deriving it per package. Must not
alter existing gate, delivery or revocation semantics — this documents and binds
the existing lane, it does not build a parallel one.

## Outcome

Session of 2026-08-11: T01 published the S3 platform-service pattern; T03, T04
and T05 routed their proposals to the owning repos (reef-railiance
f0f44ce0, railiance-master 04c776c4, the-custodian cc64764a). T02 was
held until railiance-master settled the schema.

Session of 2026-08-13: T02 done. `rapp-openbao` and `rapp-postgres`
`declarations/rapp.yaml` now pass `schemas/rapp.schema.json` (contract
metadata, `composition`, `bound_reefs: [reef-railiance]`, `commands`,
`smoke_contract.required`, `rollback_contract.order`). Live inventory for
the T06 coverage check is
`docs/evidence/reef-railiance-deployables.json`, refreshable with
`scripts/capture-reef-deployables.py`. Family-validator remainder is
outside this task: `rapp-qonto` still on the pre-schema shape, three
undeclared `rapp-*` engine repos, and `reef-railiance` `bound_rapps`
still hand-listed.

Session of 2026-08-13 (later): T06 done. Binding recipe is
`docs/rapp-credential-lane-binding.md`. Standing secrets bind through
a CCR `target.rapp` + `secret_references`; short-lived leases bind
through grant `rapp_id` (required when the grant id is `rapp-*/…`).
Stamped `rapp-postgres` catalog grants and `CCR-2026-0009`. Gate,
delivery, and revocation semantics are unchanged. Workplan finished.
