railiance-platform/workplans/RPF-WP-0043-policy-nexus-argocd-onboarding.md
custodian-sync 288c40b9e9 chore(consistency): renormalize lifecycle state [auto]
Updated by fix-consistency on 2026-09-21:
  - workplan status: ready → active

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

9 KiB

id type title domain repo status flavor owner topic_slug created updated due related state_hub_workstream_id
RPF-WP-0043 workplan Onboard rapp-policy-nexus to the ArgoCD production lane financials railiance-platform active planning railiance-platform railiance 2026-09-21 2026-09-21 2026-12-21
RPF-WP-0022
ec41a4bd-df18-5b07-9b63-ccb80d9f001c

The founder, Bernd Worsch, decided on 2026-09-21, exercising GOVERN @ estate, that changes to production-approved workloads go through CONSTRUCT @ the manifest repository, reconciled by ArgoCD through railiance-apps-root. The record is the-custodian/docs/kubernetes-change-gate-decision.md. Terms follow SecurityCanon Mode of Authority v0.2.0, which is still a draft.

rapp-policy-nexus is production-approved (reef-railiance bindings/rapps.yaml), but no ArgoCD Application manages it. Its changes today are Helm releases, make deploy in rapp-policy-nexus: helm upgrade --install policy-nexus on railiance01, namespace policy-nexus. Until 2026-12-21 those changes keep activation=APPROVED by founder plan approval, and each one is recorded as production-tier. This plan onboards policy-nexus by 2026-12-21.

This plan only prepares the change. It does not perform it. Adding argocd/applications/policy-nexus.application.yaml is a live production change. Once it is on main, railiance-apps-root syncs it with prune and self-heal, and ArgoCD takes ownership of running resources. Nothing in this plan is applied, pushed as an Application, or synced without the founder's go-ahead (T04).

Out of scope: the legacy whynot-design npm location (RPF-WP-0035-T07). It stays untouched and unwrapped while this lane moves.

Confirm ArgoCD actually reconciles on railiance01

id: RPF-WP-0043-T01
status: todo
priority: high
state_hub_task_id: "d6a7a480-6251-504a-aa5f-ab9c04fe1e79"

This repository cannot confirm it; see docs/argocd-gitops.md § Production Change Path. The only record of ArgoCD's health is from 2026-06 and predates the correction of the railiance01/coulombcore naming. Later records call the controller "coulombcore ArgoCD", and all Applications target kubernetes.default.svc.

Attended, read-only, against a kubeconfig whose server is verified to be 92.205.62.239:

  1. kubectl get nodes -o wide: confirm the node IP.
  2. kubectl -n argocd get deploy,sts and make argocd-status.
  3. kubectl -n argocd get application railiance-apps-root -o jsonpath='{.status.sync.status} {.status.health.status} {.status.sync.revision}'. Compare the revision with Forgejo main.

Record the output as docs/evidence/<date>-argocd-railiance01-status.json. If ArgoCD is absent or not syncing on railiance01, stop this plan. Report to the founder and the-custodian that the production row has no working path. An ArgoCD install belongs to the cluster layer and needs its own go-ahead.

Agree where policy-nexus's manifests live

id: RPF-WP-0043-T02
status: wait
priority: high
state_hub_task_id: "49143c5e-a455-526e-a26f-403dc2fb075a"

Per the tenant contract, workload manifests stay in the tenant repository. rapp-policy-nexus owns that repository (forgejo.coulomb.social/coulomb/rapp-policy-nexus) and decides this itself. We coordinate through the hub and do not decide it here.

Proposal to put to rapp-policy-nexus:

  • The source is the existing chart helm/policy-nexus.
  • A committed values file, for example k8s/railiance/values-railiance01.yaml, pins image.digest, publicationManifestDigest, sourceInventoryDigest and sourceSetDigest. Today they are passed as --set-string at deploy time. After adoption, a release is a commit that changes these pins.
  • helm.releaseName: policy-nexus, so that rendered names and the app.kubernetes.io/instance label match the live release.
  • Once adopted, make deploy / helm upgrade stops being a production path. It would fight self-heal. Whether to keep it for pre-production is for rapp-policy-nexus to decide.

Platform checks:

  • The chart renders Deployment, Service, ServiceAccount, Ingress and NetworkPolicy. All five are in the railiance-tenants whitelist.
  • Repository access: if the repository is private, it needs an ArgoCD repository credential at platform/operators/argocd/repositories/rapp-policy-nexus. That credential goes through its own CCR. No value is handled in this plan.

Unblock: rapp-policy-nexus replies with the path, the values file, and whether the repository is public.

Prepare the Application and the dry-run evidence

id: RPF-WP-0043-T03
status: wait
priority: high
state_hub_task_id: "2afb1aac-66dd-5e1e-92e1-fc020a59a927"

Draft the Application in this workplan or in a review branch, not under argocd/applications/ on main. Draft shape for adoption:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: policy-nexus            # no finalizers: deletion must not cascade
  namespace: argocd
  labels:
    app.kubernetes.io/part-of: railiance-gitops
spec:
  project: railiance-tenants
  source:
    repoURL: https://forgejo.coulomb.social/coulomb/rapp-policy-nexus.git
    targetRevision: <pinned commit>
    path: helm/policy-nexus
    helm:
      releaseName: policy-nexus
      valueFiles: [<agreed values file>]
  destination:
    server: https://kubernetes.default.svc
    namespace: policy-nexus
  syncPolicy:                   # adoption stage: no `automated` block
    syncOptions:
      - CreateNamespace=false
      - ApplyOutOfSyncOnly=true
      - PruneLast=true

Read-only evidence to collect before T04, in an attended session:

  1. helm -n policy-nexus get values policy-nexus and helm history: the live digests and the current revision number, which is the rollback target. Do not print anything else from the release.
  2. Render the chart with the agreed values file. Run kubectl diff --server-side of the render against the live namespace. Expected result: no spec change, and only label or annotation differences.
  3. List every object in policy-nexus. Mark which ones the render does not contain, for example Helm release Secrets sh.helm.release.v1.*. Only resources carrying ArgoCD's tracking label are pruned. Confirm that none of the unrendered objects carry it.

Stop conditions: any Deployment spec or image change, any object that the render lacks but that carries the tracking label, or a digest mismatch.

Adopt policy-nexus (live, founder go-ahead)

id: RPF-WP-0043-T04
status: wait
priority: high
state_hub_task_id: "8638fa73-439d-5dcd-85c7-81aa125170e1"

Waits on the founder's go-ahead. This is a CONSTRUCT @ railiance-platform change with activation=APPROVED. The merge is the gate, and it is a live production change. Do not take it on the basis of this plan alone.

  1. Merge the Application exactly as in T03, with no automated sync. railiance-apps-root creates the Application object. It does not touch policy-nexus resources, because the child has no automated sync.
  2. argocd app diff policy-nexus, or read the UI diff. It must match T03 step 2. Any other result means stop, then roll back (step R1).
  3. argocd app sync policy-nexus with pruning left off, which is the default for a manual sync. Then run rapp-policy-nexus make verify-live with the pinned digests.
  4. After the workload has been Synced and Healthy for at least 24 hours, a second merge adds automated: {prune: true, selfHeal: true}, matching the tenant contract. This needs a second go-ahead.
  5. Record evidence as docs/evidence/<date>-policy-nexus-argocd-adoption.json. Notify rapp-policy-nexus and ops-mason that policy-nexus is now in the production row. Its transition exception ends.

Rollback:

  • R1, before step 4: revert the merge commit. The root app prunes the child Application object. The child has no finalizer, so the deletion does not cascade and the workload keeps running unchanged.
  • R2, after step 4: revert the automated-sync commit first, then R1. Do not patch the child Application by hand, because the root app's self-heal restores it from git. A hand patch is a direct ADMINISTER under BREAK_GLASS. It is recorded and reconciled back into git.
  • Workload restore: only after ArgoCD no longer manages policy-nexus, run rapp-policy-nexus make rollback REVISION=<revision from T03>. Otherwise self-heal fights the rollback.

Declare the platform's own direct-apply gap

id: RPF-WP-0043-T05
status: todo
priority: medium
state_hub_task_id: "91431560-79d4-5352-a6b5-f12850315dd2"

Under the decision, platform objects without a readiness state default to the production tier. This repository still changes several of them through direct Make targets. Examples are the railiance01 ClusterSecretStores, OpenBao configuration and the ArgoCD bootstrap. That is target-audited evidence only. Inventory those targets, declare the gap as not conforming, and propose to the founder which ones move to a reconciled lane and which stay direct under APPROVED. Do not change a target's behaviour as part of the inventory.