RPF-WP-0018 T01-T06: publish S3 posture, placement policy, quotas, ADR surface

T01 docs/tenancy-posture.md - vector set per service rather than one repo
vector, with the provider-versus-consumer finding routed to net-kingdom.
T02/T03/T06 docs/placement-policy.md - accepts placement ownership scoped
to rule-here/number-there, records a placement owner per workload, reports
the latency-critical + batch co-residency on platform-pg, marks the
connection-ceiling trigger unmonitored pending railiance-telemetry, and
answers the retention floor/ceiling question.
T04 s3-consumer-interfaces 1.1.0 - quota disclosure per SS10.2. Surfaces
that apps-pg has no backup, no resource limits and no tuned parameters.
T05 docs/adr/ created with a mandatory-frontmatter convention and the
first three ADRs. This repo previously held none.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
codex 2026-08-17 21:55:11 +02:00
parent b83194741d
commit e7e4e33bb8
9 changed files with 809 additions and 12 deletions

View file

@ -0,0 +1,67 @@
---
title: "ADR-0001 — S3 owns platform services, not the substrate beneath them"
status: accepted
revision: "1.0"
owner: railiance-platform
date: "2026-08-17"
last_reviewed: "2026-08-17"
review_interval: 12m
---
# ADR-0001 — S3 owns platform services, not the substrate beneath them
## Context
`railiance-platform` is S3 on the OAS Stack: the shared services several
applications depend on — PostgreSQL, secrets, cache, object storage. The layers
around it are S1 `railiance-infra` (OS and host concerns), S2
`railiance-cluster` (Kubernetes runtime, ingress), S4 `railiance-enablement`
(tooling and CI), S5 `railiance-apps` (workloads).
This boundary has been stated in `SCOPE.md` and in ADR-003 of `railiance-infra`
since the five-repo split, and it has been tested twice. `RAIL-PL-WP-0001`
existed to extract platform services *out* of S2 subcharts. On 2026-08-17
`POLICY-NEXUS-WP-0001` assigned this repo "the substrate — DNS, TLS, ingress,
hosting" for `policy.coulomb.social`, which would move the boundary back the
other way.
The pressure is predictable and will recur: S3 is the layer that looks like it
owns infrastructure, because it owns things that feel infrastructural. Recording
the rule as an ADR rather than as a line in `SCOPE.md` gives future requests
something to be answered against.
## Decision
**S3 owns shared platform *services* and the interfaces consumers bind to. It
does not own DNS, TLS, Kubernetes ingress, host configuration, or CI.** A
request that would place any of those here is redirected to S1, S2 or S4 rather
than absorbed, even when this repo is the closest available owner and even when
absorbing it would be faster.
Where S3 has a genuine part in such a request — an object-storage bucket, a
credential lane, a database — it supplies that part and co-signs the rest. It
does not become the owner of the whole by being the first repo asked.
## Consequences
- `POLICY-NEXUS-WP-0001` T04 needs splitting: ingress and TLS to S2, DNS to S1
or the reef boundary, storage and credentials here. Routed as `RPF-WP-0018`
finding F1.
- A request this repo declines does not thereby become nobody's. Declining
carries an obligation to name the owner, which is why F1 names two.
- The rule cuts against this repo's convenience in the common case. That is
what makes it a rule rather than a preference.
- `rapp-openbao` and `rapp-postgres` are the same principle applied inward:
the deployable package left, custody and policy stayed. See
`docs/rapp-openbao-boundary.md` and `docs/rapp-postgres-boundary.md`.
## Alternatives considered
**Accept the substrate assignment as written.** Fastest, and the requester had
already resolved it with the operator. Rejected: it re-imports the coupling
`RAIL-PL-WP-0001` spent a workplan removing, and a boundary that yields to
whoever asks most recently is not a boundary.
**Own ingress for S3-adjacent services only.** A narrower version, and it fails
on the first argument about what counts as adjacent. The line has to be drawn
where it can be checked.

View file

@ -0,0 +1,81 @@
---
title: "ADR-0002 — S3 owns the placement rule; the package repo owns the number"
status: proposed
revision: "1.0"
owner: railiance-platform
date: "2026-08-17"
last_reviewed: "2026-08-17"
review_interval: 6m
---
# ADR-0002 — S3 owns the placement rule; the package repo owns the number
## Context
`net-kingdom/canon/standards/tenancy-posture_v0.1.md` §8.2 proposes that
database placement policy — dedicated versus shared, and when that changes —
be owned by `railiance-platform`, co-signed by `adaptive-pricing`.
`tenant-engine` raised the same gap independently on 2026-08-16: both patterns
are live on railiance01, neither is written down, and each new service copies
whichever neighbour it looked at.
The complication is that this repo no longer holds the specs. `RAILIANCE-WP-0012`
and `RAILIANCE-WP-0015` moved the deployable surface to the `rapp-*` repos.
`platform-pg`'s `instances`, `max_connections`, memory limit and retention are
`rapp-postgres`'s cluster CR. Tenancy Posture §19.8 nonetheless asks *this repo*
for `platform-pg`'s declared maximum size — a question one hop from where its
answer lives.
Accepting ownership without stating this would produce either an answer we
cannot substantiate or a quiet non-answer.
## Decision
**Accept placement ownership, split along rule and number.**
*This repo owns the rule:* the default placement level, what overrides it, who
is accountable for each workload's placement, that a shared cluster must publish
a ceiling and an overflow target before its third consumer, that retention has a
floor and a ceiling, and that a consumer's erasure horizon on shared substrate
is disclosed rather than inherited silently.
*The package repo owns the number:* what the ceiling actually is, which resource
binds first, what the retention values are, and the validator that enforces them
where the CR lives.
**Placement ownership per workload sits with the consuming repo; this repo
co-signs.** The consumer knows its latency requirement, erasure horizon and
compliance position; S3 knows the substrate. A placement change needs both.
Putting the decision solely here would recreate the problem §8.2 exists to
avoid — an operations-shaped repo holding a commercial decision alone.
`adaptive-pricing` co-signature is requested, not assumed.
## Consequences
- `docs/placement-policy.md` is the operative document; this ADR is the
decision behind it.
- §19.8 is answered by obligation rather than by number: Rule P-4.1 requires
`platform-pg` and `apps-pg` to declare a ceiling before their third consumer.
Both are at two consumers.
- This repo owes `apps-pg`'s ceiling under its own rule. A policy whose author
is exempt is not a policy.
- §8.1 requires triggers to be *monitored*. This repo has no monitoring plane,
so the connection-and-memory-ceiling trigger is recorded `unmonitored`
pending `railiance-telemetry`. Declaring a ceiling is a partial substitute —
a written threshold is checkable by a human at provisioning, which beats a
limit discovered by an OOM kill.
- If `adaptive-pricing` declines, this ADR is revised to record single
ownership explicitly rather than leaving an unsigned co-signature line.
## Alternatives considered
**Decline ownership; route it to `rapp-postgres`.** They hold the specs and the
operational knowledge. Rejected: placement is a cross-cluster question and
`rapp-postgres` owns one package. A policy owned by one substrate's operator
cannot govern movement between substrates.
**Accept whole, including the numbers.** Rejected: it would either re-import
the deployable surface this repo deliberately gave up, or produce numbers
restated here that drift from the CR — a second source of truth for exactly the
values a consumer must be able to trust.

View file

@ -0,0 +1,67 @@
---
title: "ADR-0003 — Decisions that bind others live in docs/adr, not only in the State Hub"
status: accepted
revision: "1.0"
owner: railiance-platform
date: "2026-08-17"
last_reviewed: "2026-08-17"
review_interval: 12m
---
# ADR-0003 — Decisions that bind others live in `docs/adr`, not only in the State Hub
## Context
This repo recorded decisions with the State Hub's `record_decision()` and wrote
governing content as prose in `docs/` — 24 files on 2026-08-17, none carrying a
status, owner, revision or review date. It held no ADRs at all.
Two things made that a defect rather than a style.
**The hub is a read model.** The estate's standing rule is that local files are
the source of truth and the hub reflects them. A decision that exists only as a
hub record inverts that for the one class of content where it matters most.
**`policy-nexus` publishes canon and ADRs only**, globbing `docs/adr/*.md` from
each repo. A repo with no ADRs is invisible to the estate's publication surface
no matter how much governing content it holds. This repo owns S3 boundary
rules, the credential-lane model and the consumption-mode gate — all binding on
other repos, all unpublishable.
The gap was structural, not an oversight: nothing in the session protocol ever
told anyone to write an ADR here.
## Decision
**A decision that binds anyone outside this repo is recorded as an ADR in
`docs/adr/`, with the frontmatter in `docs/adr/README.md`, before or alongside
any hub record.** The hub record points at the ADR; it does not replace it.
Runbooks and procedures stay as prose in `docs/` and stay unpublished. The test
is not importance — several runbooks are critical — but whether the document
*decides* something for someone else.
## Consequences
- `docs/adr/` exists, with a convention, a template and this repo's first three
ADRs.
- Existing prose is not converted wholesale. Content is promoted when it is
next touched, or when a consumer needs to cite it.
- `last_reviewed` and `review_interval` are mandatory here, which is stricter
than the estate norm — of 69 ADRs across 19 repos on 2026-08-17, 21 had YAML
frontmatter and 2 had any notion of a review date. `POLICY-NEXUS-WP-0001` T05
cannot compute staleness without those fields and must not invent them, since
inventing them would make the publication a second source of truth, which is
that workplan's own top risk. Routed as `RPF-WP-0018` finding F5.
- Session protocol guidance should follow, so the next agent writes an ADR
without being told. Not done in this ADR.
## Alternatives considered
**Keep decisions in the hub and have `policy-nexus` read it.** Rejected on
both sides: it would make a read model authoritative, and it would give the
publication surface a source that no repo can diff or review.
**Add frontmatter to all 24 existing `docs/` files.** Rejected. Most are
runbooks that should not be published, and stamping them with a status would
assert a decision that was never made.

69
docs/adr/README.md Normal file
View file

@ -0,0 +1,69 @@
---
title: "ADR convention for railiance-platform"
status: accepted
revision: "1.0"
owner: railiance-platform
date: "2026-08-17"
last_reviewed: "2026-08-17"
review_interval: 12m
---
# ADRs in this repo
Work record: `RPF-WP-0018` T05.
Until 2026-08-17 this repo held **no ADRs**. Its decisions lived either as
prose in `docs/` without status or ownership, or in the State Hub via
`record_decision()`. Both are wrong homes, for the same reason: the hub is a
read model and prose is not addressable as a decision. `policy-nexus`
publishes canon and ADRs only, so a repo with no ADRs publishes nothing —
regardless of how much governing content it holds. See `ADR-0003`.
## What gets an ADR here
A decision gets an ADR when it **binds someone other than the person who made
it** — another repo, a future maintainer, or a consumer of an S3 interface.
| Content | Home | Published |
| --- | --- | --- |
| A decision binding others | `docs/adr/` | yes |
| A procedure someone follows | `docs/*.md` runbook | no |
| Live interface values | `docs/s3-consumer-interfaces.md` | no |
| Work sequencing | `workplans/` | no |
Runbooks stay prose deliberately. A site that publishes everything publishes
nothing in particular, and `POLICY-NEXUS-WP-0001` T03 already draws that line.
## Frontmatter is mandatory
Every ADR carries the YAML block below. The fields are not decoration: they
are exactly what `POLICY-NEXUS-WP-0001` T02 and T05 consume to render a page
and to mark it stale.
```yaml
---
title: "ADR-NNNN — short imperative statement of the decision"
status: proposed | accepted | superseded | withdrawn
revision: "1.0"
owner: railiance-platform
date: "YYYY-MM-DD" # when decided
last_reviewed: "YYYY-MM-DD"
review_interval: 6m | 12m # after which the page shows as stale
supersedes: ADR-NNNN # optional
superseded_by: ADR-NNNN # optional
---
```
`last_reviewed` and `review_interval` are the two fields the rest of the estate
mostly lacks — of 69 ADRs across 19 repos on 2026-08-17, 2 carried any notion
of a review date. A publication surface cannot compute staleness without them
and must not invent them, so they are required here.
Numbering is `ADR-NNNN`, four digits, never reused. A superseded ADR keeps its
number and its file; it gains `superseded_by` and its status changes. Nothing
is deleted — the published URL must keep resolving.
## Sections
Context · Decision · Consequences · Alternatives considered. Keep the decision
statement to one paragraph a reader can quote.