--- id: RPF-WP-0020 type: workplan title: "Close CCR schema drift: one active lane unmigrated, one draft the suite cannot express" domain: financials repo: railiance-platform status: proposed owner: codex topic_slug: railiance created: "2026-08-18" updated: "2026-08-18" related: - RPF-WP-0014 origin: residual origin_ref: RPF-WP-0019 state_hub_workstream_id: "e2da7c94-0693-40fa-a339-1873b7dd061a" --- # RPF-WP-0020 — CCR schema drift ## Goal Make `tests/test_credential_change.py::test_all_repo_ccrs_validate` pass for the right reason: because every credential-change request in the repo is either valid or explicitly declared in-flight — not because the assertion was loosened until it stopped complaining. ## Why this is its own workplan The test has been failing on `main`. It was found while closing `RPF-WP-0019` and confirmed to predate that work (it fails at `HEAD` with the apps-pg changes stashed), so it is neither a regression from that workplan nor something to fix inside it. A single red test is hiding **two unrelated problems with opposite remedies**. That is the reason to split them out and name them, rather than fix whichever one makes the suite green first. ## The two problems **P1 — an active credential lane is unmigrated.** `credential-change-requests/CCR-2026-0010-email-connect-transactional.yaml` carries `status: active` and `readiness: ready`, and is missing the entire `openbao.auth` block: `method`, `mount`, `role`, `policies`, `bound_claims`. The validator gained those requirements and this CCR was never brought forward. This is the one that matters. A live lane whose declaration does not describe how the workload authenticates is a governance gap, not a lint failure — the document that is supposed to be the authority on the lane cannot answer the first question anyone would ask of it. The lane itself is presumably working, which is exactly what makes it easy to leave. **P2 — a genuine in-flight draft the suite cannot express.** `CCR-2026-0011-scaleway-object-storage-bootstrap.yaml` carries `status: apply_pending` and `readiness: waiting-on-ui-replace-of-xxx-placeholders`. It is a founder-bootstrap credential still holding placeholder values, and `ops-warden` already tracks it as a draft lane. Its errors include a `readiness` value outside the permitted enum, which is the file honestly reporting that it is not finished. This one is not a defect. The defect is that a suite asserting *all* CCRs validate has no way to say "this one is deliberately incomplete", so an honest draft and a real gap produce identical output. ## Boundaries - **No secret values are read, written or rotated.** This is declaration hygiene. Anything requiring a mint, a rotation or an apply belongs to the credential-change approval flow in `docs/credential-change-approval.md`. - P2 is not closed by filling in placeholders. The Scaleway bootstrap key is a live commercial credential with an owner outside this repo. - The validator's rules are not relaxed to accommodate either file. ## Tasks ```task id: RPF-WP-0020-T01 status: todo priority: high state_hub_task_id: "3bf8bf9c-ac33-4ce7-8b3f-5b40135b227c" ``` **Migrate CCR-2026-0010 to the current schema.** Determine the actual authentication path for the `email-connect` transactional lane — Kubernetes auth mount, role, bound claims, and the policy name that must match `openbao.policy_name` — from the live OpenBao configuration and the existing policy file, not by inventing plausible values. If the live configuration and the declaration disagree, the live configuration is the fact and the disagreement is the finding. ```task id: RPF-WP-0020-T02 status: todo priority: medium state_hub_task_id: "12933d69-82a3-470d-b01c-0c40c28a7984" ``` **Give the suite a way to express a draft.** Add an explicit in-flight state so `CCR-2026-0011` is skipped *by declaration* rather than by exception list — a `status` the validator recognises as not-yet-complete, with the test asserting that such files are still well-formed in every other respect. An allowlist of filenames would work today and rot on the next draft. ```task id: RPF-WP-0020-T03 status: todo priority: medium state_hub_task_id: "da52b518-c6fb-40b8-acb9-c64724ca4eee" ``` **Report the drift rather than only fixing it.** If the `openbao.auth` requirement was added without migrating existing active CCRs, other repos carrying CCRs may have the same gap and no failing test to reveal it. Confirm whether the requirement originated here or upstream, and notify accordingly. ```task id: RPF-WP-0020-T04 status: todo priority: low state_hub_task_id: "2259ee69-4914-42c4-9175-8c61b2206888" ``` **Make the suite green and keep it that way.** With T01 and T02 done, the full suite passes. Record in `docs/credential-change-approval.md` that a new required field obliges a migration pass over existing active CCRs — the omission that produced P1. ## Risks **T01 invents values to make the test pass.** The likeliest failure and the worst one: a declaration that is well-formed and wrong is more dangerous than one that is visibly incomplete, because it stops anyone looking. Mitigation is that T01 reads live configuration and treats disagreement as a finding. **T02 becomes a way to silence future failures.** Mitigation is that the in-flight state still requires the file to be well-formed in every other respect, so it suppresses the completeness assertion and nothing else.