ops-mason/workplans/MASON-WP-0006-readiness-tier-check.md
tegwick c3424f730e chore(consistency): write back MASON-WP-0006 hub IDs and refresh WORK-RECORDS.md
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 63291@bnt-lap001
Assistant-Session: 8bd77868-ca68-4f49-bb1e-d539ecc0d703
2026-09-21 14:37:25 +02:00

8.1 KiB

id type title domain repo status flavor owner topic_slug created updated state_hub_workstream_id
MASON-WP-0006 workplan Check the target's readiness tier before a direct Kubernetes apply infotech ops-mason proposed implementation claude ops-mason 2026-09-21 2026-09-21 1b900161-51ff-544f-8412-ba7fcab64bb5

MASON-WP-0006 — Check the target's readiness tier before a direct Kubernetes apply

Goal

Make phase 4 enforce the founder's Kubernetes change-gate decision (the-custodian/docs/kubernetes-change-gate-decision.md, 2026-09-21, the founder exercising GOVERN @ estate). Before any direct ADMINISTER @ realm:kubernetes/railiance01, ops-mason plane apply must establish the target's railiance-master ADR-0006 readiness_state and:

  • allow a direct apply under activation=APPROVED (founder plan approval) when the target is declared, installed or verified;
  • refuse a direct apply to a production-tier target (production-approved, or no readiness state at all), except:
    • under activation=BREAK_GLASS, which is recorded and must be reconciled back into the manifest repository afterwards; or
    • for rapp-policy-nexus under the transition, which runs until 2026-12-21. Each such change keeps activation=APPROVED and is recorded as production-tier, so the transition does not look like conformance.

The production path itself (CONSTRUCT @ manifest repository, reconciled by ArgoCD) belongs to railiance-platform. ops-mason only refuses; it does not build that path.

Boundaries

  • The executor's limits are not widened. One expected namespace per plan, Pod and Secret refused, no data or stringData. The decision relies on them; widening any of them is a new founder decision.
  • The readiness check is a quality gate, not an authorization decision. It does not consult access-engine and must not be described as a PDP.
  • No live change is part of this workplan. Tests use the injected runner.

Design choice: how ops-mason obtains the readiness state

The authoritative states live in another repository, reef-railiance/bindings/rapps.yaml. Three options were weighed:

  1. Read the sibling checkout at apply time. Simple, but unpinned: the evidence would name no revision, and the result depends on whatever the workstation happens to have checked out.

  2. Vendor a copy of rapps.yaml into ops-mason. Pinned, but it goes stale silently. A rApp promoted to production-approved upstream would still read as verified here and pass the gate: the failure mode is fail-open.

  3. Pin the reference in the bundle and verify it against the source at preflight (chosen). The bundle names the target and pins the readiness source the same way it already pins manifests:

    readiness:
      target: {kind: rapp, rapp_id: rapp-user-engine}   # or {kind: platform}
      source:
        repo: reef-railiance
        path: bindings/rapps.yaml
        revision: <commit>
        sha256: <digest of the file at that commit>
    

    Preflight, through the existing runner:

    • git -C <reef-railiance> show <revision>:bindings/rapps.yaml must hash to sha256;
    • git -C <reef-railiance> diff --quiet <revision> HEAD -- bindings/rapps.yaml must show the file unchanged since the pin, so a later promotion cannot be missed. If the file changed, the bundle is re-pinned through review;
    • the readiness_state for the target is read from the pinned content.

    Fail closed. A missing readiness block, kind: platform, a target not listed in rapps.yaml, a source that cannot be found or verified, or an unknown state value all resolve to the production tier. The decision says platform objects without a readiness state default to production; an unverifiable state is treated the same way.

    The checkout location comes from a --readiness-repo CLI option, defaulting to the sibling path ../reef-railiance. It is a location, not a trust anchor: the pinned revision and digest are.

The evidence record gains a readiness section: target, source repo, revision and digest, resolved state, tier, activation, and a transition flag when the policy-nexus rule was used.

Open question for the founder: the whitehat plane

id: MASON-WP-0006-T01
status: wait
priority: high
state_hub_task_id: "7b6fe7b4-08f7-5ad0-899d-a4862b5ddb00"

bundles/whitehat-foundational-plane.yaml is the only bundle today, and its plan is built. It targets the whitehat namespace, which is not a rApp and carries no ADR-0006 readiness_state. Under the decision it therefore defaults to the production tier, and once T03 lands, a further direct apply of it would be refused.

This workplan was told the check must not change behaviour for today's non-production plans. Whether the whitehat plane is one of them is not a question ops-mason can answer for itself. The founder chooses one of:

  • (a) it is a platform object and production-tier, as the default says; future changes to it go through the manifest repository or BREAK_GLASS;
  • (b) it gains a readiness state from its owner (whitehat-security), in which case readiness.target names that record; or
  • (c) an explicit, dated exception.

T03 must not merge before this is answered.

Extend the bundle schema with the readiness block

id: MASON-WP-0006-T02
status: todo
priority: high
state_hub_task_id: "89d07bd5-5a92-5a06-9ecb-441799c14dd7"

Add the optional readiness block to PlaneBundle.load as described above. It is included in the bundle digest, as the bundle file already is. Add a --activation {APPROVED,BREAK_GLASS} option to plane apply, defaulting to APPROVED, and a --readiness-repo option. BREAK_GLASS requires a --break-glass-reason string. No existing refusal is relaxed.

Enforce the tier in preflight and apply

id: MASON-WP-0006-T03
status: todo
priority: high
state_hub_task_id: "163a807b-29aa-5eb7-a9a8-ef1ac70c89d3"

Add a pure function, resolve_tier(state, target, activation, today), returning the tier and whether a direct apply is allowed, and call it from apply after the plan-approval and digest checks and before any kubectl write. preflight reports the resolved tier without refusing, so a production-tier plane can still be validated.

Tests, all against the injected runner:

  • a verified rApp target applies under APPROVED (non-production tier);
  • a production-approved target is refused under APPROVED, with no kubectl apply call made;
  • the same target is allowed under BREAK_GLASS, and the evidence records it;
  • rapp-policy-nexus is allowed under APPROVED on 2026-12-20, is recorded with transition: true and tier production, and is refused on 2026-12-22;
  • no readiness block, kind: platform, an unlisted rApp, a digest mismatch, and a file changed since the pin each resolve to production and are refused;
  • the existing forbidden-kind, data/stringData and namespace tests still pass unchanged.

Record BREAK_GLASS and its reconcile-back obligation

id: MASON-WP-0006-T04
status: todo
priority: medium
state_hub_task_id: "66349531-09ee-55b9-be47-537842c80f3b"

A BREAK_GLASS apply writes its reason, actor and time into the evidence record and prints the follow-up that is owed: the same change, committed to the manifest repository that ArgoCD reconciles. ops-mason does not open that change itself.

Update the docs and the declaration

id: MASON-WP-0006-T05
status: todo
priority: medium
state_hub_task_id: "6d64e7f5-9cff-5bf9-9851-97d318d1df0a"

Update docs/kubernetes-plane.md with the tier table and the readiness block, and change the enforcement line of the kubernetes-plane-apply entry in INTENT.md from "not yet in code" to point at the check.

Review on 2026-12-21

id: MASON-WP-0006-T06
status: wait
priority: medium
state_hub_task_id: "49dd5f9a-307b-5baf-809e-bd3893c73341"

On 2026-12-21 the policy-nexus transition ends and the plan-approval exception comes up for review. Confirm with railiance-platform that policy-nexus is onboarded to ArgoCD. The date check in T03 ends the transition in code on that date either way.