issue-core/workplans/ISSUE-WP-0007-rapp-issue-core-railiance01-migration.md
custodian-sync a705e0885e chore(consistency): renormalize lifecycle state [auto]
Updated by fix-consistency on 2026-08-19:
  - workplan status: ready → active
2026-08-19 20:23:48 +02:00

12 KiB

id type title domain repo status owner lane topic_slug priority created updated reviewed_at quality_dor quality_dor_at quality_dor_by quality_dor_note depends_on related state_hub_workstream_id
ISSUE-WP-0007 workplan rapp-issue-core: move the runtime off CoulombCore onto railiance01 infotech issue-core active codex yellow issue-core high 2026-08-19 2026-08-19 2026-08-19 DoR-Ok 2026-08-19 codex Goal, ownership, task order, dependencies, safety gates, and verification signals reviewed against the issue-core repo and current rapp family.
ISSUE-WP-0003
ACTIVITY-WP-0023
RMGR-WP-0006
RMGR-WP-0007
a2bc717a-64cf-45fa-8a9d-59d3bc9e96c7

ISSUE-WP-0007 — rapp-issue-core: move the runtime onto railiance01

CoulombCore is being decommissioned. issue-core is one of three services still running there, and it is the load-bearing one: the ops-bridge tunnel issue-core-railiance01 is a reverse forward that re-exports this workstation's 18765 to railiance01, so railiance01 reaches issue-core through a laptop that is forwarding to CoulombCore. When CoulombCore goes, issue-core goes with it, and deleting the tunnel is not a migration.

Start here: what ISSUE-WP-0003 actually proved

ISSUE-WP-0003 is status: finished and its opening summary incorrectly says that railiance01 reconciles issue-core through ArgoCD. Its own 2026-07-02 completion section records the topology correction: the Deployment and ArgoCD Application were on CoulombCore, while railiance01 reached them through the two-hop ops-bridge lane.

Checked on 2026-08-19 against the railiance01 cluster (~/.kube/config-railiance01, bridge tunnel k3s-api-railiance01, local 16444):

Claim Observed
Deployment live in issue-core namespace Namespace exists, emptyNo resources found
Reconciled by ArgoCD No ArgoCD — the cluster has no applications resource type
issue-core serving Serving from CoulombCore: -L 18765:10.43.103.154:8765, /healthz{"status":"ok","version":"0.2.1"}

No railiance01 deployment was silently lost: the first deployment landed on the wrong cluster and was then deliberately bridged to railiance01. The correction is recorded in history/2026-08-19-wp-0003-topology-correction.md and at the top of WP-0003. Treat its container, secret, service, and authenticated-ingest evidence as prior art, but do not resume its ArgoCD topology.

Why a rapp- wrapper rather than k8s/railiance/ in this repo

issue-core currently carries its own Dockerfile and k8s/railiance/ Kustomize tree. The estate has since settled on a different split, visible in rapp-postgres, rapp-qonto, rapp-user-engine, rapp-tenant-engine, rapp-openbao, rapp-secrets-engine, rapp-policy-nexus: domain logic stays in the app repo; runtime packaging, bindings, secret references, network policy, placement, and rollout evidence live in a rapp-<app> repo.

rapp-qonto/README.md states the boundary plainly: "Domain logic and financial policy stay in qonto-assistant. This repo owns runtime packaging, the Knative binding, secret references, network policy, and workload-specific rollout evidence."

That split is also what makes the loss above visible next time: rollout evidence is a deliverable of the wrapper, not a side effect of a cluster being up.

repo-manager scaffolds these — do not hand-build one:

rmgr rapp wrap --path ../rapp-issue-core --app issue-core \
  --ownership-repo issue-core --from-app ../issue-core \
  --rail rail-kubernetes \
  --package-type manifest-managed-platform-service
rmgr rapp validate --path ../rapp-issue-core --family-root ..
rmgr rapp place --path ../rapp-issue-core --reef reef-railiance

The reviewed values for this workload are rail-kubernetes, manifest-managed-platform-service, confidential, and high. It remains a private cluster service. See repo-manager/docs/RailianceAppDeploymentGuide.md (RMGR-WP-0006) and RMGR-WP-0007 (greenfield rapp wrap efficiency).

Consumers to carry across

Migration is not done when a pod is Running. These reach issue-core today:

  • activity-coreIssueSink emission. ops-warden routes this need as catalog id activity-core-issue-sink.
  • ops-bridge — tunnels issue-core-coulombcore (-L 1876510.43.103.154:8765) and issue-core-railiance01 (reverse re-export). Both are retired by this work; the second one should not be recreated in any form.
  • Anything reading http://127.0.0.1:18765 on the workstation.

Scope and human gate

In scope: create and register rapp-issue-core; transfer the runtime package; deploy it privately on railiance01; prove health, auth, Forgejo creation, failure, and rollback; cut optional REST consumers over; then remove the legacy bridge and tunnels.

Out of scope: changing issue-core domain behaviour, adding Postgres, selecting Knative, granting public exposure, changing activity-core's fleet-wide default away from State Hub, or storing secret values in repo/Hub evidence.

This is a yellow-lane production migration. T02/T03 are reversible file work. The T04 live cluster apply and the T05 removal of bridge/tunnel infrastructure require explicit implementation authorization; tunnel removal additionally requires the recorded direct-path 201 gate.

T00 — Correct the historical topology record

id: ISSUE-WP-0007-T00
status: done
priority: high
state_hub_task_id: "a195fe94-0231-4dd8-b75e-94f50fec86bc"

Correct the WP-0003 topology record. Done 2026-08-19. WP-0003's own completion evidence shows that ArgoCD and the issue-core Deployment were on CoulombCore, not railiance01; railiance01 consumed the service through a two-hop bridge. Added a prominent correction to WP-0003 and recorded the finding in history/2026-08-19-wp-0003-topology-correction.md. This was a recording/topology error, not evidence of a railiance01 workload being pruned.

T01 — Settle the packaging decisions

id: ISSUE-WP-0007-T01
status: done
priority: high
state_hub_task_id: "2ab2dd49-1c69-4f8e-a807-ce078d2899ce"

Settle the packaging decisions. Done 2026-08-19 against the current repo, the live rapp family, and RailianceAppDeploymentGuide.md:

  • primary rail: rail-kubernetes — this is a long-running private API; it has no request-activation, scale-to-zero, or revision-traffic requirement;
  • package type: manifest-managed-platform-service — absorb the current Kustomize manifests rather than inventing a Helm chart;
  • data classification: confidential — issue titles/bodies and mapping metadata may contain internal work context;
  • criticality: high — external tracker projection fails when it is down, but the file/State-Hub work-record spine continues;
  • database: none for the production wrapper — the production backend is Forgejo; SQLite is an optional offline/local backend, so do not pass --dedicated-postgres and remove any generated Postgres-consumer draft;
  • exposure: private; no Ingress or public grant.

Reviewed scaffold command:

UV_CACHE_DIR=/tmp/issue-core-rmgr-cache uv run --directory ../repo-manager \
  rmgr rapp wrap --path ../rapp-issue-core --app issue-core \
  --ownership-repo issue-core --from-app ../issue-core \
  --rail rail-kubernetes \
  --package-type manifest-managed-platform-service \
  --classification confidential --criticality high \
  --purpose "Package and operate the issue-core external-tracker connector on Railiance."

T02 — Scaffold and register rapp-issue-core

id: ISSUE-WP-0007-T02
status: progress
priority: high
state_hub_task_id: "e0427de0-dfac-4848-ba2d-1421167eb704"

Scaffold rapp-issue-core via rmgr rapp wrap, then rmgr rapp validate --path ../rapp-issue-core --family-root ... Remove the generated Postgres-consumer draft because this deployment uses Forgejo, then revalidate. Do not hand-author the baseline layout; the validator encodes the family conventions and will reject a bespoke tree. Register the new repo the normal file-first way and run its consistency check rather than creating Hub records by hand.

T03 — Transfer the runtime package

id: ISSUE-WP-0007-T03
status: todo
priority: high
state_hub_task_id: "d6e5e2ac-7f42-412f-8143-91531f5155e8"

Port the runtime package. Keep Dockerfile, docker-entrypoint.sh, source, tests, and .forgejo/workflows/image.yaml in issue-core; the app repo builds and publishes the image. Move k8s/railiance/ into the wrapper's manifest shape, including the private Service, ServiceAccount, default-deny plus explicit NetworkPolicy, and OpenBao-backed secret references. Pin a Forgejo OCI image by immutable digest; do not reuse the retired Gitea registry tag as the release contract.

Delete issue-core/k8s/railiance/ and retire docs/argocd-gitops.md only after the wrapper contains an equivalent, validated runtime contract and retained handoff. Two active sources of deployment truth are not allowed.

T04 — Place, deploy, and prove the direct service

id: ISSUE-WP-0007-T04
status: todo
priority: high
state_hub_task_id: "21974fbd-4962-4732-b407-c531bb2ebfe6"

Place, deploy, and prove it on railiance01. Run rmgr rapp place --path ../rapp-issue-core --reef reef-railiance --family-root .., then deploy through the wrapper's reviewed apply surface. Credential custody remains in OpenBao: route ISSUE_CORE_API_KEY through catalog issue-core-ingestion-api-key and route the Forgejo PAT through the concrete platform/OpenBao lane (never log or commit either value).

Record secret-free live evidence in the wrapper for: rollout and Ready state; image digest match; /healthz 200 from inside the cluster; unauthenticated POST /issues/ rejected; authenticated controlled POST /issues/ returning 201 through forgejo-inbox; dependency failure returning a bounded 503; NetworkPolicy presence; and rollback to the previous immutable digest. Follow the reversible rapp-qonto/tools/verify_live.sh evidence style.

Evidence that the service answers only via an ops-bridge tunnel does not count. That is the condition being retired.

T05 — Cut consumers over and retire tunnels

id: ISSUE-WP-0007-T05
status: todo
priority: high
state_hub_task_id: "3fdbd9ab-3e3f-4ac0-8763-77278a1cc6e6"

Cut consumers over, then retire the tunnels. Point activity-core's optional REST IssueSink endpoint directly at the new in-cluster Service and remove its bridge Deployment/Service. Keep the fleet default ISSUE_SINK_TYPE=state-hub; rest remains an explicit external-projection opt-in, not a global cutover. Prove one controlled activity-core-shaped request returns 201 before asking ops-warden to update catalog id activity-core-issue-sink.

Inventory any other consumers of workstation port 18765. Only once they are cut over, ask ops-bridge to remove issue-core-coulombcore and issue-core-railiance01 from ~/.config/bridge/tunnels.yaml.

Order matters: removing the tunnels first takes issue-core down for everyone still pointed at 127.0.0.1:18765.

T06 — Close out and notify dependants

id: ISSUE-WP-0007-T06
status: todo
priority: medium
state_hub_task_id: "668e37dc-8ebe-46cc-9a27-905440b1240c"

Close out. Update SCOPE.md, retire the obsolete ArgoCD runbook, sync both repos' work records, and tell activity-core, ops-warden, and ops-bridge that the direct Service is authoritative and CoulombCore has one fewer dependency. Remaining CoulombCore services after this: core-hub-staging and inter-hub.

Implementation order and gates

  1. T02 may create/register the wrapper, but does not bind compute or apply.
  2. T03 must leave a schema-valid, digest-pinned, secret-free runtime package.
  3. T04 binds and deploys only after T03 validation and the OpenBao references are confirmed; its 201 smoke is the promotion gate.
  4. T05 changes consumers only after T04; tunnel retirement is last.
  5. T06 closes only after direct-path evidence and tunnel removal are recorded.

Notes for whoever picks this up

  • ops-bridge tunnel map header (~/.config/bridge/tunnels.yaml) lists what is left on CoulombCore and why.
  • railiance01 cluster access: kubectl --kubeconfig ~/.kube/config-railiance01 (tunnel k3s-api-railiance01, local 16444). There is no CoulombCore kubeconfig any more — its k3s-api tunnel was removed on 2026-08-19, so inspecting the current deployment needs that tunnel restored first.
  • Reviewed 2026-08-19 in issue-core and promoted from proposed to ready.