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:
parent
b83194741d
commit
e7e4e33bb8
9 changed files with 809 additions and 12 deletions
|
|
@ -20,6 +20,7 @@
|
|||
| workplan | RAILIANCE-WP-0016 | finished | — | workplans/RAILIANCE-WP-0016-apps-pg-resource-evidence.md |
|
||||
| workplan | RAILIANCE-WP-0016 | finished | — | workplans/RAILIANCE-WP-0016-architecture-cleanup-backlog.md |
|
||||
| workplan | RAILIANCE-WP-0017 | finished | — | workplans/RAILIANCE-WP-0017-consumption-mode-enforcement.md |
|
||||
| workplan | RPF-WP-0018 | proposed | — | workplans/RPF-WP-0018-policy-surface-alignment.md |
|
||||
| task | RAILIANCE-WP-0005-T01 | done | — | workplans/RAILIANCE-WP-0005-credential-request-and-lease-broker.md |
|
||||
| task | RAILIANCE-WP-0005-T02 | done | — | workplans/RAILIANCE-WP-0005-credential-request-and-lease-broker.md |
|
||||
| task | RAILIANCE-WP-0005-T03 | done | — | workplans/RAILIANCE-WP-0005-credential-request-and-lease-broker.md |
|
||||
|
|
@ -80,3 +81,10 @@
|
|||
| task | RAILIANCE-WP-0016-T04 | done | — | workplans/RAILIANCE-WP-0016-architecture-cleanup-backlog.md |
|
||||
| task | RAILIANCE-WP-0016-T05 | done | — | workplans/RAILIANCE-WP-0016-architecture-cleanup-backlog.md |
|
||||
| task | RAILIANCE-WP-0017-T01 | done | — | workplans/RAILIANCE-WP-0017-consumption-mode-enforcement.md |
|
||||
| task | RPF-WP-0018-T01 | todo | — | workplans/RPF-WP-0018-policy-surface-alignment.md |
|
||||
| task | RPF-WP-0018-T02 | todo | — | workplans/RPF-WP-0018-policy-surface-alignment.md |
|
||||
| task | RPF-WP-0018-T03 | todo | — | workplans/RPF-WP-0018-policy-surface-alignment.md |
|
||||
| task | RPF-WP-0018-T04 | todo | — | workplans/RPF-WP-0018-policy-surface-alignment.md |
|
||||
| task | RPF-WP-0018-T05 | todo | — | workplans/RPF-WP-0018-policy-surface-alignment.md |
|
||||
| task | RPF-WP-0018-T06 | todo | — | workplans/RPF-WP-0018-policy-surface-alignment.md |
|
||||
| task | RPF-WP-0018-T07 | todo | — | workplans/RPF-WP-0018-policy-surface-alignment.md |
|
||||
|
|
|
|||
67
docs/adr/ADR-0001-s3-platform-service-boundary.md
Normal file
67
docs/adr/ADR-0001-s3-platform-service-boundary.md
Normal 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.
|
||||
81
docs/adr/ADR-0002-placement-policy-ownership.md
Normal file
81
docs/adr/ADR-0002-placement-policy-ownership.md
Normal 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.
|
||||
67
docs/adr/ADR-0003-decisions-live-in-the-repo.md
Normal file
67
docs/adr/ADR-0003-decisions-live-in-the-repo.md
Normal 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
69
docs/adr/README.md
Normal 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.
|
||||
224
docs/placement-policy.md
Normal file
224
docs/placement-policy.md
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
# S3 database placement policy
|
||||
|
||||
Work record: `RPF-WP-0018` T02, T03, T06
|
||||
Effective: 2026-08-17
|
||||
Framework: `net-kingdom/canon/standards/tenancy-posture_v0.1.md` §4.4, §8
|
||||
Contract version of this document: `1.0.0`
|
||||
Status: **provisional** — binding on this repo now; formally conditional on
|
||||
the framework reaching `accepted` and on `adaptive-pricing` co-signature.
|
||||
|
||||
Answers `tenant-engine`'s 2026-08-16 request ("a default and the conditions
|
||||
that override it, so migrations stop being decided by whichever neighbour was
|
||||
consulted") and Tenancy Posture §19.2.
|
||||
|
||||
## 1. Ownership, and its limit
|
||||
|
||||
§8.2 proposes placement ownership to `railiance-platform` co-signed by
|
||||
`adaptive-pricing`. **Accepted, with the scope stated:**
|
||||
|
||||
> **This repo owns the rule. The package repo owns the number.**
|
||||
|
||||
We decide *that* a cluster must publish a ceiling, what happens when it is
|
||||
reached, what the default placement is, and who is accountable for each
|
||||
workload's placement. We do not decide what `platform-pg`'s `max_connections`
|
||||
is — that is `rapp-postgres`'s cluster CR, and `RAILIANCE-WP-0012` /
|
||||
`RAILIANCE-WP-0015` moved that surface there deliberately.
|
||||
|
||||
This matters for §19.8, which asks *this repo* for `platform-pg`'s declared
|
||||
maximum size. That question is misrouted by one hop. `rapp-postgres`'s own
|
||||
analysis makes the case better than we could: memory probably binds before
|
||||
connections do, at roughly 10MB per backend against a 1Gi limit, and that is
|
||||
an observation only the operator of the package can make. Our obligation under
|
||||
this policy is §4 below — that a ceiling and an overflow target **exist and
|
||||
are published**. Theirs is what they are.
|
||||
|
||||
`adaptive-pricing` co-signature is **requested, not assumed**. The reasoning in
|
||||
§8.2 is sound: tenancy model selection is commercial as much as technical. If
|
||||
they decline, this document records single ownership and says so plainly rather
|
||||
than leaving a co-signature line nobody signed.
|
||||
|
||||
## 2. The default, and what overrides it
|
||||
|
||||
The ladder is `net-kingdom` canon and is not restated here. Adopted by
|
||||
reference: P0–P4 per Tenancy Posture §4.4.
|
||||
|
||||
**Default: P1 — database per consumer, shared cluster** — for platform
|
||||
services. P3 for client-facing business apps, per
|
||||
`business-app-service-contract` §1.2. Both already ratified as Decision 4.4.1;
|
||||
this document adopts rather than re-decides them.
|
||||
|
||||
**P0 is not a sanctioned target.** It is the state repos arrive in. A consumer
|
||||
sharing a database with another consumer is a defect with a migration owed,
|
||||
not a placement.
|
||||
|
||||
**The distinction `tenant-engine` asked us to preserve, preserved:** sharing a
|
||||
*cluster* is a capacity decision and is cheap to undo — create target, dump,
|
||||
restore, swap the `secretKeyRef`, restart. Sharing a *database* entangles
|
||||
schemas and makes relocation a schema merge. This policy says "shared" only
|
||||
ever in the first sense. Any consumer on an S3-custody cluster owns a whole
|
||||
database.
|
||||
|
||||
**Portability is an expectation, not a courtesy.** A consumer connects by
|
||||
injected URL only; no cluster, namespace, host or database name in source.
|
||||
`tenant-engine` adopted this unprompted and it is hereby the rule, because a
|
||||
placement policy that cannot be executed is a preference.
|
||||
|
||||
## 3. Placement owner per workload
|
||||
|
||||
§19.2 asks for a recorded owner per workload so that "should this be dedicated"
|
||||
has an answer that is not archaeology. The **placement owner** decides
|
||||
placement changes for that workload and is accountable for watching its
|
||||
triggers. It is not the same role as the operator of the cluster.
|
||||
|
||||
| Workload | Substrate | Provided level | Placement owner | Co-signer |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `audit-core` | `platform-pg` | P1 | `audit-core` | this repo |
|
||||
| `tenant-engine` | `platform-pg` | P1 | `tenant-engine` | this repo |
|
||||
| `user-engine` | `user-engine-pg` | P2 | `net-kingdom` | this repo |
|
||||
| `target-revenue` | `target-revenue-pg` | P2 | `target-revenue` | this repo |
|
||||
| `forgejo` | `forgejo-db` | P2 | this repo | — |
|
||||
| `vergabe` | `apps-pg` | P1 | `vergabe-teilnahme` | this repo |
|
||||
| `coulomb_social` | `apps-pg` | P1 | `coulomb-social` | this repo |
|
||||
|
||||
**The consuming repo is the placement owner; this repo co-signs.** The
|
||||
consumer knows its latency requirement, its erasure horizon and its compliance
|
||||
position; we know the substrate. Neither can decide alone, and putting the
|
||||
decision solely here would recreate the "ops repo holds a commercial decision"
|
||||
problem §8.2 exists to avoid. A placement change needs both signatures.
|
||||
|
||||
New consumers record a placement owner at provisioning. A provisioning request
|
||||
without one is incomplete.
|
||||
|
||||
## 4. Ceiling and overflow — the §19.8 obligation, generalised
|
||||
|
||||
**Rule P-4.1.** Every shared cluster under S3 policy MUST publish a **declared
|
||||
maximum consumer count** and a **named overflow target**, both before its
|
||||
third consumer is provisioned.
|
||||
|
||||
**Rule P-4.2.** The ceiling is stated as the *binding* constraint with its
|
||||
number, not as a capacity boast. Where more than one resource could bind
|
||||
first — connections versus memory is the live case — the declaration names
|
||||
which is expected to bind and why. A ceiling derived from the resource that
|
||||
fails *cleanly* while another fails *catastrophically* is a mis-stated ceiling:
|
||||
connection exhaustion errors and is recoverable, memory pressure OOM-kills and
|
||||
degrades every co-resident at once.
|
||||
|
||||
**Rule P-4.3.** The overflow target is a named substrate, not "we will build
|
||||
one". "Provision a second cluster" is an answer; "revisit at the time" is not.
|
||||
|
||||
**Status against these rules today:**
|
||||
|
||||
| Cluster | Ceiling declared | Overflow target | Standing |
|
||||
| --- | --- | --- | --- |
|
||||
| `platform-pg` | not yet — `rapp-postgres` owes it | not yet | **2 consumers of ~6 practical; owed before the 3rd** |
|
||||
| `apps-pg` | not yet — this repo owes it | not yet | 2 consumers; owed before the 3rd |
|
||||
| `forgejo-db` | n/a — single consumer | n/a | — |
|
||||
|
||||
Both live shared clusters are one consumer away from the trigger. This repo
|
||||
owes `apps-pg`'s ceiling under its own rule, which is the correct asymmetry: a
|
||||
policy whose author is exempt is not a policy.
|
||||
|
||||
## 5. Triggers, and who is watching them
|
||||
|
||||
§8.1: triggers MUST be **monitored**, not merely recorded. *"A trigger in a
|
||||
YAML comment nobody re-reads is documentation, not control."*
|
||||
|
||||
This repo has no monitoring plane. `SCOPE.md` records that S3 emits to
|
||||
`railiance-telemetry` "once the evidence plane exists — seeded 2026-08-11, not
|
||||
yet implemented". Rather than claim coverage we do not have — the overclaim
|
||||
§6 prohibits — each trigger below carries either a named watcher or the
|
||||
literal marker `unmonitored`.
|
||||
|
||||
| # | Trigger (§8) | Signal that would fire it | Watcher | Cadence |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Noisy neighbour on a latency-critical path | Query latency regression on the consumer's own path | **consumer-observed** — the consumer notices, we do not | on incident |
|
||||
| 2 | Compliance or residency requirement | Consumer declares it | placement owner | at declaration |
|
||||
| 3 | Plan tier requiring a higher minimum | `adaptive-pricing` tier definition names a P floor | `adaptive-pricing` | on tier change |
|
||||
| 4 | Erasure horizon no longer fits | Consumer's declared horizon < cluster retention floor | placement owner + this repo | at provisioning, then `unmonitored` |
|
||||
| 5 | Connection or memory ceiling reached | Backend count vs declared ceiling; memory vs limit | **`unmonitored` — pending `railiance-telemetry`** | — |
|
||||
|
||||
**Trigger 5 is the one that matters and it is the one nobody is watching.**
|
||||
That is the honest position. It is also why Rule P-4.1 forces the ceiling to be
|
||||
declared *before the third consumer*: a threshold that is written down is at
|
||||
least checkable by a human at provisioning time, which is strictly better than
|
||||
a limit discovered by an OOM kill. Declaring the ceiling is a partial substitute
|
||||
for monitoring it, and it is the part we can do this week.
|
||||
|
||||
**Closing trigger 5 belongs to `railiance-telemetry`, not to this workplan.**
|
||||
Recorded here as a dependency so it is visible rather than assumed.
|
||||
|
||||
## 6. Service class co-residency — the §8.3.3 report
|
||||
|
||||
§8.3.2 declares service class as a category, never a priority. §8.3.3 requires
|
||||
the platform to report which classes are co-resident, because "an unenforceable
|
||||
risk that nobody can see is strictly worse than one that is stated".
|
||||
|
||||
| Cluster | Co-resident classes | Mismatch |
|
||||
| --- | --- | --- |
|
||||
| `platform-pg` | `latency-critical` (`tenant-engine`) + `batch` (`audit-core`) | **yes — reported** |
|
||||
| `apps-pg` | `interactive` + `interactive` | no |
|
||||
| `forgejo-db` | single consumer | n/a |
|
||||
|
||||
**`platform-pg` mixes `latency-critical` with `batch` today.** Under §8.3.1
|
||||
co-residents are equal — community PostgreSQL has no resource governor, so
|
||||
nothing prioritises `tenant-engine`'s synchronous authorization queries over
|
||||
`audit-core`'s batch work. `tenant-engine` chose a 5s statement timeout
|
||||
precisely because it sits on `flex-auth`'s synchronous path.
|
||||
|
||||
This is **reported, not remediated**. It may well still be the right call —
|
||||
§8.3.2 says a recognised mismatch "may still be the right call, but it should
|
||||
be a decision, not an accident of who was provisioned when". It is now a
|
||||
decision. The escalation, if the mismatch bites, is P2 for `tenant-engine`, and
|
||||
the known alternative — gateway-level prioritisation in a connection proxy — is
|
||||
infrastructure this estate does not run and is not adopted here.
|
||||
|
||||
## 7. Retention floor and ceiling — the §19.9 answer
|
||||
|
||||
**Answered: yes to both, as a rule; the numbers belong to the package repo.**
|
||||
|
||||
**Rule R-7.1 — floor.** A consumer's requested `backupRetentionDays` below the
|
||||
cluster's declared floor is a **validation error at provisioning**, not a quiet
|
||||
disappointment. A consumer that asks for 1 day and silently gets 30 has been
|
||||
told nothing true; a consumer that gets an error learns the actual constraint
|
||||
at the only moment it can act on it.
|
||||
|
||||
**Rule R-7.2 — ceiling.** A maximum exists so no consumer can exhaust the
|
||||
backup volume. Exceeding it is likewise an error, and the remedy named in the
|
||||
error is P2 — a dedicated cluster whose retention is the consumer's own.
|
||||
|
||||
**Rule R-7.3 — the floor is a placement trigger, and this is the important
|
||||
one.** Per `rapp-postgres` ADR-0002, physical backup is instance-wide, so on a
|
||||
shared cluster **a consumer's erasure horizon is the maximum declared across
|
||||
all co-residents**. A consumer needing a horizon shorter than that floor
|
||||
**cannot have it at P1** and must move to P2 — for a reason that has nothing to
|
||||
do with performance or capacity, which is exactly why it must be recorded
|
||||
rather than assumed.
|
||||
|
||||
This makes someone else's retention choice everyone's, which is what
|
||||
`tenant-engine` warned about on 2026-08-16 and was right to. Rule R-7.4
|
||||
follows.
|
||||
|
||||
**Rule R-7.4 — inherited retention is disclosed, not inherited silently.** A
|
||||
consumer joining a shared cluster is told its effective erasure horizon at
|
||||
provisioning, and told again when a co-resident's change moves it. This is
|
||||
§10.2 applied to retention and is implemented in
|
||||
`docs/s3-consumer-interfaces.md` 1.1.0.
|
||||
|
||||
**Enforcement is the package repo's.** The validator lives where the CR lives.
|
||||
This document states the rule; `rapp-postgres` and this repo's own `apps-pg`
|
||||
onboarding enforce it.
|
||||
|
||||
## 8. What this policy deliberately does not do
|
||||
|
||||
- **It moves no workload.** Declaring where things are is separate from
|
||||
changing where they are. Nothing above is a migration instruction.
|
||||
- **It adds no QoS axis.** §19.12 resolved that: we could not enforce one.
|
||||
- **It does not decide identity-provider placement** (realm-per-tenant versus
|
||||
Organizations, §19.7). That is `key-cape`'s, on a different substrate.
|
||||
- **It claims no monitoring.** See §5.
|
||||
|
||||
## Review interval
|
||||
|
||||
Six months, or on: a new shared-cluster consumer, a co-residency class change,
|
||||
`railiance-telemetry` going live, or the framework reaching `accepted`. Next
|
||||
review due **2027-02-17**.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
# S3 consumer service interfaces
|
||||
|
||||
Work record: `RAILIANCE-WP-0016` item 17
|
||||
Date: 2026-08-15
|
||||
Contract version of this index: `1.0.0`
|
||||
Work record: `RAILIANCE-WP-0016` item 17; `RPF-WP-0018` T04
|
||||
Date: 2026-08-15, revised 2026-08-17
|
||||
Contract version of this index: `1.1.0`
|
||||
|
||||
Consumers bind to these contracts, not to Helm chart names or pod topology.
|
||||
Changing an engine behind a versioned interface does not bump the interface
|
||||
|
|
@ -27,6 +27,26 @@ unless the consumer-visible fields change.
|
|||
`postgresql-ha-pgpool.platform.svc.cluster.local` is **not** an
|
||||
interface. That stack is retired.
|
||||
|
||||
## Quota disclosure
|
||||
|
||||
Added in `1.1.0` — additive, so no consumer contract breaks.
|
||||
|
||||
Tenancy Posture §10.2: *quotas are disclosed, not discovered.* Every consumer
|
||||
is told at provisioning what the platform will refuse to do for it, and told
|
||||
again when that changes. **A consumer learning its statement timeout by hitting
|
||||
it in production is a disclosure failure, not a consumer bug.**
|
||||
|
||||
The obligation this places on S3 is a standing one: a change to any value in
|
||||
the tables below is announced to bound consumers before it takes effect. The
|
||||
values themselves are read from the cluster CR and are the package owner's to
|
||||
set — this index publishes them, it does not choose them.
|
||||
|
||||
Retention disclosure carries the additional §7 rule from
|
||||
`docs/placement-policy.md`: on a shared cluster the **effective erasure
|
||||
horizon is the maximum declared across co-residents**, not the value the
|
||||
consumer requested. That number is disclosed, and it moves when a co-resident
|
||||
changes.
|
||||
|
||||
## `apps-pg.v1`
|
||||
|
||||
Consumer supplies: app name, namespace, database name, role name. Platform
|
||||
|
|
@ -35,6 +55,30 @@ provisions the role and CNPG `Database`, labels the namespace
|
|||
RW endpoint: `apps-pg-rw.databases.svc.cluster.local:5432`. Bootstrap
|
||||
role `apps_admin` is not a consumer credential.
|
||||
|
||||
**Quotas and limits** — read from `helm/apps-pg-cluster.yaml`, 2026-08-17:
|
||||
|
||||
| Property | Value | Note |
|
||||
| --- | --- | --- |
|
||||
| `max_connections` | **PostgreSQL default (100)** | Not tuned in the CR. Not partitioned per consumer — there is no per-consumer connection allowance, so one consumer can exhaust the cluster. |
|
||||
| `statement_timeout` | **none** | Not set. A runaway query runs until it finishes. |
|
||||
| `idle_in_transaction_session_timeout` | **none** | Not set. |
|
||||
| CPU / memory limits | **none declared** | The pod is BestEffort QoS and is the first thing evicted under node pressure. |
|
||||
| Instances | 1 | No HA. Restart recovery only, per the single-node rail. |
|
||||
| Storage | 10Gi | |
|
||||
| Backup | **none configured** | No `barmanObjectStore`, no `retentionPolicy`. |
|
||||
| Effective erasure horizon | **undefined** | Follows from the line above. |
|
||||
|
||||
**Read the backup row before provisioning against this cluster.** `apps-pg`
|
||||
has no backup at all — not a short retention, none. Recovery from data loss is
|
||||
not available on this interface today. This is disclosed rather than fixed
|
||||
because §10.2 requires disclosure now and the fix needs a backup target; it is
|
||||
recorded as the R-axis gap in `docs/tenancy-posture.md` and is the highest
|
||||
value item that declaration surfaced.
|
||||
|
||||
The unpartitioned connection pool is the same shape of risk `rapp-postgres`
|
||||
reported for `platform-pg`: the bound is aggregate, so every consumer can be
|
||||
politely inside its own expectations while the cluster still fails.
|
||||
|
||||
## `rapp-postgres.v1`
|
||||
|
||||
Consumer is a `consumers[].declaration`. Boundary unit is
|
||||
|
|
@ -42,6 +86,26 @@ Consumer is a `consumers[].declaration`. Boundary unit is
|
|||
`openbao-dynamic-database-credential` via grant
|
||||
`rapp-postgres/<consumer>-<role>`. Tenant identifiers are opaque.
|
||||
|
||||
**Quotas and limits** — authority is `rapp-postgres`'s
|
||||
`helm/platform-pg-cluster.yaml`; reproduced here for disclosure, 2026-08-17:
|
||||
|
||||
| Property | Value | Note |
|
||||
| --- | --- | --- |
|
||||
| `max_connections` | 100 | Aggregate, not per consumer. ~14 per consumer (12 runtime + 2 migration) puts the practical ceiling near 6. |
|
||||
| Memory limit | 1Gi | Expected to bind before connections do — ~10MB per backend. Memory pressure OOM-kills; connection exhaustion errors cleanly. |
|
||||
| CPU | 100m request / 1 limit | |
|
||||
| Instances | 1 | No HA. |
|
||||
| Storage | 20Gi | |
|
||||
| Backup retention | 30d | Instance-wide, per `rapp-postgres` ADR-0002. |
|
||||
| Effective erasure horizon | **30d, or the max across co-residents** | A consumer needing shorter cannot have it at P1. See `docs/placement-policy.md` §7. |
|
||||
| Statement timeout | consumer-set | `tenant-engine` sets 5s for its own path; not a platform default. |
|
||||
| Declared ceiling / overflow target | **not yet declared** | Owed by `rapp-postgres` before the third consumer, per `docs/placement-policy.md` Rule P-4.1. |
|
||||
|
||||
Service classes currently co-resident on `platform-pg`: `latency-critical`
|
||||
(`tenant-engine`) and `batch` (`audit-core`). Nothing prioritises between them
|
||||
— community PostgreSQL has no resource governor. Reported per Tenancy Posture
|
||||
§8.3.3.
|
||||
|
||||
## `ccr-workload-kv.v1` and `credential-grant.v1`
|
||||
|
||||
Unchanged semantics from `docs/credential-change-approval.md` and
|
||||
|
|
|
|||
177
docs/tenancy-posture.md
Normal file
177
docs/tenancy-posture.md
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# S3 tenancy posture declaration
|
||||
|
||||
Work record: `RPF-WP-0018` T01
|
||||
Declared: 2026-08-17
|
||||
Framework: `net-kingdom/canon/standards/tenancy-posture_v0.1.md` (draft-5, proposed)
|
||||
Contract version of this document: `1.0.0`
|
||||
|
||||
This is `railiance-platform`'s response to the Tenancy Posture ratification
|
||||
test (§20.2): *"Each publishes its own posture vector as part of review. The
|
||||
framework is validated by whether it can describe them accurately."*
|
||||
|
||||
It declares under §6 — **conformance is accuracy, not altitude**. Several
|
||||
levels below are `0`. None of them is an admission of weakness, and §6 is
|
||||
explicit that a declared low level is conformant while an unevidenced high
|
||||
level is not.
|
||||
|
||||
## Why this is a vector *set* and not a vector
|
||||
|
||||
§5 asks a **service** for one level per axis. `railiance-platform` is an OAS
|
||||
**layer** holding custody of several services with materially different
|
||||
postures. A single vector for the repo would be an average of things that are
|
||||
not alike, which is the inaccuracy §6 prohibits.
|
||||
|
||||
So: one vector per service, plus an explicit statement of what this repo owns
|
||||
versus what it merely holds policy for. The distinction matters because
|
||||
`RAILIANCE-WP-0012` and `RAILIANCE-WP-0015` deliberately moved the deployable
|
||||
surface to the `rapp-*` repos while custody and policy stayed here.
|
||||
|
||||
| Service | This repo's relationship | Deployable owned by |
|
||||
| --- | --- | --- |
|
||||
| `apps-pg` | **owns** — cluster CR is `helm/apps-pg-cluster.yaml` | this repo |
|
||||
| `forgejo-db` | **owns** — cluster CR is `helm/forgejo-db-cluster.yaml` | this repo |
|
||||
| `openbao` | **custody and policy**; package extracted | `rapp-openbao` |
|
||||
| `platform-pg` | **policy only**; consumer contract and grants here | `rapp-postgres` |
|
||||
| Valkey, MinIO | declared capability, no live instance | — |
|
||||
|
||||
## The vectors
|
||||
|
||||
### `apps-pg` — shared cluster for S5 application databases
|
||||
|
||||
```yaml
|
||||
tenancy:
|
||||
service: apps-pg
|
||||
role: storage-provider
|
||||
current: { I: 0, A: 0, E: 0, P: null, R: 0 }
|
||||
target: { I: 0, A: 0, E: 0, P: null, R: 2 }
|
||||
service_class: interactive
|
||||
reviewed: "2026-08-17"
|
||||
gap:
|
||||
R: "No backup is configured on this cluster at all — no barmanObjectStore,
|
||||
no retentionPolicy, no deletion path. R0 is the accurate reading and
|
||||
it is worse than it looks: R0 here means no recovery, not merely no
|
||||
erasure policy. Closing this is the highest-value item this
|
||||
declaration surfaced. Target R2 requires a backup target first."
|
||||
notes:
|
||||
- "I/A/E are 0 by construction, not by neglect. apps-pg holds no tenant
|
||||
concept, carries no tenant claim, and applies no tenant predicate. The
|
||||
tenant boundary for data on this cluster sits entirely in the consuming
|
||||
S5 application. See the provider note below."
|
||||
- "P is null rather than a number. See §P-axis note."
|
||||
```
|
||||
|
||||
### `forgejo-db` — dedicated cluster for the forge
|
||||
|
||||
```yaml
|
||||
tenancy:
|
||||
service: forgejo-db
|
||||
role: storage-provider
|
||||
current: { I: 0, A: 0, E: 0, P: null, R: 0 }
|
||||
target: { I: 0, A: 0, E: 0, P: null, R: 2 }
|
||||
service_class: interactive
|
||||
reviewed: "2026-08-17"
|
||||
gap:
|
||||
R: "Backup exists as a documented procedure (docs/forgejo-backup.md), not
|
||||
as a declared retention with a published erasure horizon. R2 needs the
|
||||
horizon published to the consumer, which is the point of the level."
|
||||
notes:
|
||||
- "Single-consumer cluster. Provides P2 to forgejo; is not itself at P2."
|
||||
```
|
||||
|
||||
### `openbao` — platform secrets service
|
||||
|
||||
```yaml
|
||||
tenancy:
|
||||
service: openbao
|
||||
role: credential-provider
|
||||
current: { I: 0, A: 2, E: 0, P: 0, R: 0 }
|
||||
target: { I: 0, A: 2, E: 0, P: 0, R: 1 }
|
||||
service_class: latency-critical
|
||||
reviewed: "2026-08-17"
|
||||
gap:
|
||||
R: "No retention position on audit device output or on KV version history.
|
||||
R1 (platform default) is reachable cheaply and is not yet declared."
|
||||
notes:
|
||||
- "A2 is claimed on the consumer boundary, not a tenant boundary: policy
|
||||
per workload path, bound once, centrally, in OpenBao's own policy
|
||||
engine. It is NOT delegated to flex-auth, so A3 is not claimed and is
|
||||
not currently a target — a PDP in the credential path would put
|
||||
flex-auth on OpenBao's availability path and OpenBao on flex-auth's."
|
||||
- "E is 0 on the TENANT axis and that number is misleading without this
|
||||
sentence: consumer separation in OpenBao is structural — a workload
|
||||
token's policy cannot address another workload's path at all, which is
|
||||
E4-shaped machinery. It scores 0 because the axis measures the tenant
|
||||
boundary and OpenBao has no tenant dimension. See the provider note."
|
||||
- "P0 is accurate and deliberate: one instance, every consumer shares it.
|
||||
Single-node rail; §17 scaling demands apply."
|
||||
```
|
||||
|
||||
### `platform-pg` — policy relationship only
|
||||
|
||||
Declared by `rapp-postgres`. This repo does not restate it. What this repo
|
||||
declares about it is in `docs/placement-policy.md`: the rule, the placement
|
||||
owner per consumer, and the triggers. The numbers — `instances: 1`,
|
||||
`max_connections: 100`, `1Gi`, `retentionPolicy: 30d` — are `rapp-postgres`'s
|
||||
cluster CR and its declaration to make.
|
||||
|
||||
## The P-axis note — why two entries are `null`
|
||||
|
||||
The P ladder describes **which substrate holds a tenant's data**, from the
|
||||
point of view of the workload whose data it is. `apps-pg` and `forgejo-db` are
|
||||
the substrate. Asking a cluster what its own placement level is has no
|
||||
well-formed answer: `apps-pg` *provides* P1 to each of its consumers, and
|
||||
`forgejo-db` *provides* P2 to forgejo, but neither *is* at a level.
|
||||
|
||||
Declaring `P: 1` for `apps-pg` would read as though the cluster had a
|
||||
placement, and a later reader would use it to argue about isolation. `null`
|
||||
plus the provider statement is the accurate form. This is routed as a finding.
|
||||
|
||||
## Finding routed to `net-kingdom`
|
||||
|
||||
**The five ladders describe a consumer of storage. They do not describe a
|
||||
provider of it.**
|
||||
|
||||
Every service above scores at or near zero on I, A and E, and in each case for
|
||||
the same structural reason rather than for a weakness: a storage or credential
|
||||
platform has no tenant dimension of its own. It is exactly as strong or weak as
|
||||
its consumers make it. The framework anticipates this in §3.3 and in the
|
||||
"newly absorbed repo" example, but the vector shape gives a provider no way to
|
||||
say the useful thing, which is not *what level am I at* but **what level do I
|
||||
make reachable for the workloads I hold**.
|
||||
|
||||
The concrete case is the `openbao` E line. `E: 0` is literally correct and
|
||||
actively misleading — the mechanism in place is credential-scoped structural
|
||||
separation, the same machinery E4 describes, pointed at a consumer boundary
|
||||
rather than a tenant one. A reader scanning a table of E values would rank
|
||||
OpenBao below a service doing per-query filtering in application code, which
|
||||
inverts the actual security position.
|
||||
|
||||
**Proposed amendment, offered as the first correction from review rather than
|
||||
from research (§Status observes that every correction so far came from research
|
||||
or relocation):** add a **provider declaration** beside the posture vector — a
|
||||
platform service states, per axis, the maximum level it makes reachable and
|
||||
what the consumer must do to reach it. For `apps-pg` that is: E4 unreachable
|
||||
(shared credential per consumer, no per-tenant credential), E3 reachable once
|
||||
the GUC contract exists, R2 blocked on a backup target. That is the sentence a
|
||||
consumer actually needs, and no arrangement of the five consumer ladders
|
||||
produces it.
|
||||
|
||||
This is offered as an addition, not a replacement. The consumer vector is
|
||||
right for consumers, and this repo is not asking for the ladders to be
|
||||
renumbered.
|
||||
|
||||
## What this repo accepts
|
||||
|
||||
- The P0–P4 ladder as written, by reference. It describes our estate correctly.
|
||||
- §8.1's monitoring obligation, with the deferrals stated in
|
||||
`docs/placement-policy.md` rather than silently.
|
||||
- §9.1 — no static long-lived database credentials above E0. Already how the
|
||||
credential broker works; no change needed.
|
||||
- §10.2 — quota disclosure. Landed in `docs/s3-consumer-interfaces.md` 1.1.0.
|
||||
- §6 — accuracy over altitude, which is why this document declares four zeros.
|
||||
|
||||
## Review interval
|
||||
|
||||
Six months, or on any of: a service moving placement level, a backup target
|
||||
becoming available, or the framework reaching `accepted`. Next review due
|
||||
**2027-02-17**.
|
||||
|
|
@ -4,7 +4,7 @@ type: workplan
|
|||
title: "Align S3 with the estate policy surface (Tenancy Posture + policy-nexus)"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: proposed
|
||||
status: active
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-17"
|
||||
|
|
@ -15,6 +15,7 @@ related:
|
|||
- RAPP-POSTGRES-WP-0002
|
||||
origin: routed
|
||||
origin_ref: "net-kingdom/canon/standards/tenancy-posture_v0.1.md §19.2, §20"
|
||||
state_hub_workstream_id: "d40827cb-bb48-4cdd-9b41-8dfae116d705"
|
||||
---
|
||||
|
||||
# RPF-WP-0018 — policy surface alignment
|
||||
|
|
@ -65,7 +66,7 @@ monitoring we do not have is the exact overclaim §6 prohibits, so T03
|
|||
records each trigger with a named monitor or an explicit `unmonitored`
|
||||
marker, and the marker is the honest answer until telemetry lands.
|
||||
|
||||
**Does not fit, and the policy should change.** Three findings, T07.
|
||||
**Does not fit, and the policy should change.** Five findings, T07.
|
||||
|
||||
## Findings against the policy (recommendations, not yet routed)
|
||||
|
||||
|
|
@ -131,6 +132,38 @@ has custody of — plus a statement of which it owns versus operates. T01
|
|||
does that and routes the finding back to `net-kingdom` as the framework's
|
||||
first real correction from review rather than from research.
|
||||
|
||||
Refined while writing T01: the sharper form of F4 is that **the five
|
||||
ladders describe a consumer of storage, not a provider of it.** Every S3
|
||||
service scores at or near zero on I, A and E for the same structural
|
||||
reason — a storage or credential platform has no tenant dimension of its
|
||||
own. The `openbao` E line is the demonstration: `E: 0` is literally correct
|
||||
and actively misleading, because the mechanism in place is
|
||||
credential-scoped structural separation, the machinery E4 describes,
|
||||
pointed at a consumer boundary rather than a tenant one. Proposed remedy is
|
||||
a **provider declaration** beside the consumer vector, stating per axis the
|
||||
maximum level the platform makes reachable and what the consumer must do to
|
||||
reach it. Offered as an addition, not a renumbering.
|
||||
|
||||
**F5 — `policy-nexus` T02/T05 cannot be built against the corpus as it
|
||||
stands.** Measured across the workstation on 2026-08-17: **69 ADRs in 19
|
||||
repos** — closely matching that workplan's "roughly 68 across 18" — of
|
||||
which **21 carry YAML frontmatter**, **41 carry any status field**, and
|
||||
**2 carry any notion of a review date**. T02 specifies a front-matter-driven
|
||||
renderer taking title, status, revision and review date from the source; T05
|
||||
requires every page to show status, revision and last-reviewed, with a
|
||||
staleness marker once a review interval is exceeded. Against this corpus
|
||||
that renderer has nothing to read for 48 of 69 documents, and the currency
|
||||
half of the repo's purpose has data for 2.
|
||||
|
||||
*Recommend:* T03 of that workplan should treat frontmatter as an **ingestion
|
||||
precondition**, not a rendering input — a document without the required
|
||||
fields is reported as non-conformant and left unpublished, rather than
|
||||
rendered with blanks or with dates the site inferred. Inferring them is the
|
||||
failure mode that workplan already names as its top risk: the publication
|
||||
becomes a second source of truth. The corollary is that policy-nexus needs
|
||||
a conformance report aimed at source repos before it needs a site, and this
|
||||
repo's `docs/adr/README.md` is one repo's answer to it.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- No workload moves placement level in this workplan. Declaring where
|
||||
|
|
@ -146,8 +179,9 @@ first real correction from review rather than from research.
|
|||
|
||||
```task
|
||||
id: RPF-WP-0018-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "ff392a23-e72a-4442-843f-929f218404ae"
|
||||
```
|
||||
**Publish the S3 posture vector set.** Write `docs/tenancy-posture.md`:
|
||||
one vector per service under S3 custody (`openbao`, `apps-pg`, and the
|
||||
|
|
@ -158,8 +192,9 @@ Route F4 to `net-kingdom` with the vector set as the evidence.
|
|||
|
||||
```task
|
||||
id: RPF-WP-0018-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "962fc494-bb9b-4f67-8e5b-2ed88a670945"
|
||||
```
|
||||
**Accept placement ownership, scoped.** Write `docs/placement-policy.md`:
|
||||
adopt the P0–P4 ladder by reference (do not restate it — the canon copy is
|
||||
|
|
@ -171,8 +206,9 @@ either way.
|
|||
|
||||
```task
|
||||
id: RPF-WP-0018-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "f6f30233-3f6e-44a0-a644-7268f9d88f3c"
|
||||
```
|
||||
**Make triggers monitorable or honestly unmonitored.** For each of the five
|
||||
§8 triggers, record in `docs/placement-policy.md` what signal would fire it,
|
||||
|
|
@ -184,8 +220,9 @@ report which service classes are co-resident. Today that is
|
|||
|
||||
```task
|
||||
id: RPF-WP-0018-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "8a3ce90b-8af2-4dcd-9a35-77025d2123f2"
|
||||
```
|
||||
**Disclose quotas to consumers (§10.2).** Extend
|
||||
`docs/s3-consumer-interfaces.md` to `1.1.0` — additive under its own
|
||||
|
|
@ -196,8 +233,9 @@ these is announced to bound consumers, not discovered by them.
|
|||
|
||||
```task
|
||||
id: RPF-WP-0018-T05
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "a6da631d-fa4e-4c2b-acc3-d3cf53cfb57f"
|
||||
```
|
||||
**Create the ADR surface (F2).** Create `docs/adr/` with an ADR template
|
||||
carrying the frontmatter `policy-nexus` T02/T05 consume: title, status,
|
||||
|
|
@ -210,8 +248,9 @@ only home for a decision.
|
|||
|
||||
```task
|
||||
id: RPF-WP-0018-T06
|
||||
status: todo
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "99f2a4d8-b20c-4c43-8c94-0bc469bfcc46"
|
||||
```
|
||||
**Answer §19.9 — retention floor and ceiling.** Decide whether
|
||||
`backupRetentionDays` gets a platform minimum (so a consumer asking for one
|
||||
|
|
@ -223,8 +262,9 @@ maximum declared across co-residents, so a shorter horizon is a P2 trigger.
|
|||
|
||||
```task
|
||||
id: RPF-WP-0018-T07
|
||||
status: todo
|
||||
status: progress
|
||||
priority: high
|
||||
state_hub_task_id: "b021fda3-23bd-4843-8d1b-983b6ec582b5"
|
||||
```
|
||||
**Route the findings.** Reply to `rapp-postgres` and `tenant-engine` with
|
||||
T01/T02 outcomes and F3/F4. Reply to `policy-nexus` with F1 (substrate
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue