14 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 | finished | 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. |
|
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, empty — No 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-core —
IssueSinkemission. ops-warden routes this need as catalog idactivity-core-issue-sink. - ops-bridge — tunnels
issue-core-coulombcore(-L 18765→10.43.103.154:8765) andissue-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:18765on 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-postgresand 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: done
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: done
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: done
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: done
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: done
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
- T02 may create/register the wrapper, but does not bind compute or apply.
- T03 must leave a schema-valid, digest-pinned, secret-free runtime package.
- T04 binds and deploys only after T03 validation and the OpenBao references are confirmed; its 201 smoke is the promotion gate.
- T05 changes consumers only after T04; tunnel retirement is last.
- 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(tunnelk3s-api-railiance01, local16444). There is no CoulombCore kubeconfig any more — itsk3s-apitunnel 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
proposedtoready.
Completion evidence — 2026-08-19
- Created, registered, validated, and published private repo
coulomb/rapp-issue-core; wrapper commit3003c92, State Hub workstreamb4c39759-6073-4558-a70c-2f869a31cfca. - Fixed the Forgejo lifecycle identifier contract in issue-core commit
3523a7d; published and deployed immutable digestsha256:a56c80ccbd1690bc0bcea384165b1967704f0fdbaf1c506ce1082f56190b92cf. - Full wrapper evidence passed: health 200, unauthenticated 401, authenticated create 201 + close 200, bounded dependency 503, recovery 201 + close 200, ExternalSecret ready with two keys, both NetworkPolicies present, previous digest rollback health 200, and restored-digest re-verification.
- activity-core commit
213e810now useshttp://issue-core.issue-core.svc.cluster.local:8765directly while keepingISSUE_SINK_TYPE=state-hub; a controlled worker-side request returned create 201 and close 200. - Deleted the legacy activity-core bridge resources, stopped and removed both port-18765 ops-bridge entries, and confirmed the local listener was gone.
- Retired this repo's duplicate
k8s/railiance/source and obsolete ArgoCD runbook after the wrapper was pushed and its evidence retained.