Compare commits

4 Commits
v0.2.1 ... main

Author SHA1 Message Date
8d34c6d468 docs: update issue-core deployment closeout 2026-07-01 20:04:37 +02:00
e5172611ec chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-01:
  - update .custodian-brief.md for issue-core
2026-07-01 19:39:41 +02:00
9e46004961 Update ISSUE-WP-0003 deployment progress 2026-06-25 19:59:53 +02:00
11a0a69870 Deploy issue-core 0.2.1 image 2026-06-25 19:47:58 +02:00
5 changed files with 109 additions and 83 deletions

View File

@@ -2,21 +2,17 @@
# Custodian Brief — issue-core
**Domain:** infotech
**Last synced:** 2026-06-23 12:26 UTC
**Last synced:** 2026-07-01 17:39 UTC
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
## Active Workstreams
### Deploy issue-core as a service on railiance01 (ArgoCD GitOps pilot)
Progress: 1/7 done | workstream_id: `896ace77-21b3-450b-8fb7-254aefc8c570`
Progress: 5/7 done | workstream_id: `896ace77-21b3-450b-8fb7-254aefc8c570`
**Open tasks:**
- ! ArgoCD bootstrap (railiance-platform dependency) + issue-core Application `9b199b1d`
- ! OpenBao secret: ISSUE_CORE_API_KEY `ad52527f`
- ► Kubernetes manifests (namespace, Deployment, Service) in GitOps source `38887dd6`
- ► In-cluster backend config (cluster Gitea / markitect) `10923f1e`
- ► Wire activity-core to the live service `96b14cdb`
- ► End-to-end verification + GitOps runbook `8d853b8e`
- ! Wire activity-core to the live service `96b14cdb`
- ! End-to-end verification + GitOps runbook `8d853b8e`
---
## MCP Orientation (when available)

View File

@@ -1,15 +1,10 @@
# issue-core REST ingestion service image.
#
# Installs the published issue-core[api] package from the Coulomb Gitea PyPI
# index (no sibling-checkout build context) and runs the FastAPI ingestion
# server on :8765. Built and pushed to gitea.coulomb.social/coulomb/issue-core.
# Builds the checked-out issue-core[api] package and runs the FastAPI ingestion
# server on :8765. The image is published to
# gitea.coulomb.social/coulomb/issue-core.
FROM python:3.12-slim AS runtime
ARG ISSUE_CORE_VERSION=">=0.2,<0.3"
# Do not name this PIP_INDEX_URL — Docker exposes ARGs as env vars during RUN,
# and pip treats PIP_INDEX_URL as the sole primary index (excluding PyPI).
ARG GITEA_PYPI_INDEX_URL=https://gitea.coulomb.social/api/packages/coulomb/pypi/simple/
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
HOME=/home/app
@@ -18,10 +13,11 @@ ENV PYTHONUNBUFFERED=1 \
# (~/.config/issue-tracker/backends.json).
RUN useradd --create-home --home-dir /home/app --uid 10001 app
RUN pip install --no-cache-dir \
--index-url https://pypi.org/simple \
--extra-index-url "${GITEA_PYPI_INDEX_URL}" \
"issue-core[api]${ISSUE_CORE_VERSION}"
WORKDIR /src
COPY pyproject.toml README.md LICENSE ./
COPY issue_core ./issue_core
RUN pip install --no-cache-dir --index-url https://pypi.org/simple ".[api]" \
&& rm -rf /src
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

View File

@@ -7,7 +7,7 @@ railiance-platform.
## Source layout
- Workload bundle: `issue-core/k8s/railiance/`
- Image: `gitea.coulomb.social/coulomb/issue-core:0.2.0`
- Image: `gitea.coulomb.social/coulomb/issue-core:0.2.1`
- Container port and Service port: `8765`
- Cluster Service URL: `http://issue-core.issue-core.svc.cluster.local:8765`
- Tenant Application: `railiance-platform/argocd/applications/issue-core.application.yaml`
@@ -18,31 +18,31 @@ therefore intentionally not duplicated in this bundle.
## Platform gates
The following pieces are owned by railiance-platform before the workload can
be fully reconciled:
The following pieces are owned by railiance-platform for the live pilot and for
any future cluster replay:
- ArgoCD repository credentials and the project/app-of-apps convention.
- The `issue-core` ArgoCD `Application`.
- External Secrets Operator and a `ClusterSecretStore` named `openbao`.
- OpenBao entries for the issue-core runtime Secret.
Until those gates exist, `kubectl kustomize k8s/railiance` can render locally,
but the live `ExternalSecret` and `Deployment` are expected to wait.
For the 2026-06-25 live deployment, these gates were satisfied and the
`issue-core` Application reached Synced/Healthy with image `0.2.1`.
## Secret contract
Kubernetes Secret name: `issue-core-runtime`
Current issue-core manifest path, pending railiance-platform confirmation:
Current issue-core manifest path:
```text
platform/workloads/issue-core/issue-core/issue-core-runtime
```
Credential route catalog id `issue-core-ingestion-api-key` is owned by
railiance-platform/OpenBao and is still marked draft/path TBD in the local
ops-warden catalog reviewed 2026-06-18. Confirm the canonical path before
provisioning the live Secret.
Credential custody is owned by railiance-platform/OpenBao. For agents, first
use the non-secret route catalog entry `activity-core-issue-sink` to confirm
the activity-core + issue-core pairing, and never request the value from
ops-warden.
Required properties:
@@ -56,12 +56,12 @@ HTTP status codes, and created issue URLs.
## Build and publish
Use the published package as the image input. For a reproducible release image,
pin the package version to the image tag:
Build the checked-out source tree and publish a registry tag that ArgoCD can
pull:
```bash
docker build --build-arg ISSUE_CORE_VERSION="==0.2.0" -t gitea.coulomb.social/coulomb/issue-core:0.2.0 .
docker push gitea.coulomb.social/coulomb/issue-core:0.2.0
docker build -t gitea.coulomb.social/coulomb/issue-core:0.2.1 .
docker push gitea.coulomb.social/coulomb/issue-core:0.2.1
```
The Coulomb Gitea package is public-pullable for this image, so the workload

View File

@@ -23,7 +23,7 @@ spec:
# docs). Add imagePullSecrets: [{name: gitea-registry}] if it becomes private.
containers:
- name: issue-core
image: gitea.coulomb.social/coulomb/issue-core:0.2.0
image: gitea.coulomb.social/coulomb/issue-core:0.2.1
imagePullPolicy: IfNotPresent
ports:
- name: http

View File

@@ -4,11 +4,11 @@ type: workplan
title: "Deploy issue-core as a service on railiance01 (ArgoCD GitOps pilot)"
domain: infotech
repo: issue-core
status: active
status: blocked
owner: claude
topic_slug: custodian
created: "2026-06-19"
updated: "2026-06-23"
updated: "2026-06-30"
state_hub_workstream_id: "896ace77-21b3-450b-8fb7-254aefc8c570"
---
@@ -17,36 +17,34 @@ state_hub_workstream_id: "896ace77-21b3-450b-8fb7-254aefc8c570"
`issue-core` is the authoritative task-lifecycle manager and the REST ingestion
target for activity-core's `IssueSink`. Deployment artifacts are on `main`
(`Dockerfile`, `docker-entrypoint.sh`, `k8s/railiance/`); image
`gitea.coulomb.social/coulomb/issue-core:0.2.0` is built, pushed, and
pullable. The railiance01 cluster still has no `issue-core` workload until
T02 live ArgoCD bootstrap (RAILIANCE-WP-0004-T05) and T04 OpenBao secrets land.
`gitea.coulomb.social/coulomb/issue-core:0.2.1` is built, pushed, and
pullable. The railiance01 cluster now reconciles `issue-core` through ArgoCD;
External Secrets Operator reads the OpenBao-backed runtime Secret and the
Deployment is live on port 8765.
This workplan stands up `issue-core` as a first-class in-cluster service on
railiance01 **via ArgoCD GitOps** — making issue-core the cluster's first
declarative Application and turning on the idle GitOps capability.
## Current state (verified 2026-06-19)
## Current state (verified 2026-06-25)
- **Deployment artifacts in-repo:** `Dockerfile`, `docker-entrypoint.sh`, and
`k8s/railiance/` (Kustomize: ExternalSecret, ConfigMap, Deployment, Service).
Image builds locally; `docker run` + `GET /healthz` returns 200. Image pushed
and pullable as `gitea.coulomb.social/coulomb/issue-core:0.2.0` (digest
`sha256:153fbe43…`). `coulomb` org packages are public — no `imagePullSecret`
and pullable as `gitea.coulomb.social/coulomb/issue-core:0.2.1` (digest
`sha256:729c0e56…`). `coulomb` org packages are public — no `imagePullSecret`
required per `railiance-forge/docs/gitea-container-registry.md`.
- **Dockerfile fix (2026-06-19):** build arg renamed `GITEA_PYPI_INDEX_URL`
`ARG PIP_INDEX_URL` leaked into the build env and pip used Gitea as the sole
index, so dependencies like `click` were not found.
- **railiance01 cluster:** no `issue-core` namespace; no issue-core
Deployment/Service/Pod in any namespace.
- **Dangling reference:** `activity-core/k8s/railiance/20-runtime.yaml` sets
`ISSUE_CORE_URL: http://issue-core.issue-core.svc.cluster.local:8010` — a
service that does not exist, on the **wrong port** (issue-core serves 8765) —
with `ISSUE_SINK_TYPE: "null"` so emission is disabled. It is a placeholder.
- **railiance01 cluster:** `issue-core` namespace, Service, ExternalSecret,
Secret, and Deployment are present. ArgoCD reports the `issue-core` Application
Synced/Healthy at revision `11a0a69`; pod is Ready on image `0.2.1`.
- **activity-core handoff still pending:** `activity-core/k8s/railiance/20-runtime.yaml` still points at port 8010 and keeps `ISSUE_SINK_TYPE: "null"`; T06 tracks switching it to the live issue-core service on port 8765.
- **Packaging precursor is done:** `ISSUE-WP-0002` published
`issue-core==0.2.0` to the Coulomb Gitea PyPI index.
- **ArgoCD is installed but unused:** all 7 components healthy (~290d), but
**0 Applications, 0 ApplicationSets, 0 registered git repos**, only the stock
`default` AppProject. No `kind: Application` manifests exist in any infra repo.
`issue-core==0.2.0` to the Coulomb Gitea PyPI index. The live `0.2.1` image
was built from the committed source tree as a deployment hotfix.
- **ArgoCD is active for the pilot:** railiance-platform owns the bootstrap and tenant AppProject; `issue-core` is Synced/Healthy as the pilot workload.
- **Existing deploy pattern is imperative** (the path we are *replacing* for
this service): local `docker build``k3s ctr images import` (side-load, no
registry) → `rsync` manifests → `kubectl apply` (see
@@ -61,6 +59,37 @@ declarative Application and turning on the idle GitOps capability.
traceability string. Event-driven activity-core paths can still send UUIDs;
scheduled/cron paths may now send a stable key such as `scheduled`.
## Live progress (2026-06-25)
- Added railiance-platform ESO/OpenBao plumbing and provisioned the canonical
OpenBao path `platform/workloads/issue-core/issue-core/issue-core-runtime`
with `ISSUE_CORE_API_KEY` and `GITEA_BACKEND_TOKEN` (values not logged).
- Created dedicated Gitea service user `issue-core-svc` and stored a scoped
backend token in OpenBao for issue creation.
- Published and deployed `gitea.coulomb.social/coulomb/issue-core:0.2.1`
(`sha256:729c0e56…`) with the Gitea label-payload fix and numeric UID
securityContext.
- ArgoCD `issue-core` is Synced/Healthy at `11a0a69`; ExternalSecret is Ready;
`/healthz` returns 200; authenticated `POST /issues/` returned 201 and Gitea
issue id `175`.
## Closeout recheck (2026-06-30)
- issue-core-owned deployment work remains complete: manifests, runtime secret
contract, backend config, runbook, and direct authenticated ingestion smoke are
done for image `0.2.1`.
- The remaining completion gate is the activity-core producer handoff. A
non-secret source recheck of `/home/worsch/activity-core/k8s/railiance/20-runtime.yaml`
still shows `ISSUE_CORE_URL` on port `8010` and `ISSUE_SINK_TYPE: "null"`.
- `ops-warden` routing catalog entry `activity-core-issue-sink` confirms the
lane is owned by activity-core + issue-core and that ops-warden does not vend
`ISSUE_CORE_API_KEY`.
- This WSL session does not have `kubectl` on PATH, so live ArgoCD/Kubernetes
state could not be re-polled from the workstation. Keep T06/T07 at `wait`
until the activity-core runtime is switched to the service on port `8765`,
receives the shared key through OpenBao, and an activity-core emission returns
issue-core HTTP 201 with a created Gitea issue.
## Decisions
- **Deployment method = ArgoCD GitOps** (operator decision 2026-06-19).
@@ -105,30 +134,28 @@ state_hub_task_id: "3723e896-3ec9-49b8-86f8-403993444da3"
**Goal.** A reproducible, registry-hosted image ArgoCD-managed pods can pull.
- [x] Add `Dockerfile` installing `issue-core[api]>=0.2,<0.3` from the Gitea
PyPI index (with explicit PyPI primary index). Entrypoint renders
`backends.json` then `issue serve --host 0.0.0.0 --port 8765`.
- [x] Add `Dockerfile` building the checked-out `issue-core[api]` source.
Entrypoint renders `backends.json` then `issue serve --host 0.0.0.0 --port 8765`.
- [x] Local build succeeds; `docker run` + `GET /healthz` returns 200.
- [x] Pushed `gitea.coulomb.social/coulomb/issue-core:0.2.0`; `docker pull`
- [x] Pushed `gitea.coulomb.social/coulomb/issue-core:0.2.1`; `docker pull`
succeeds.
- [x] No cluster pull secret needed (`coulomb` org packages are public).
- [ ] `POST /issues/` smoke against a running deployment (deferred to T03/T04
cluster verification).
- [x] `POST /issues/` smoke against a running deployment returned 201.
## ArgoCD bootstrap (railiance-platform dependency) + issue-core Application
```task
id: ISSUE-WP-0003-T02
status: wait
status: done
priority: high
state_hub_task_id: "9b199b1d-d3c0-4621-b8f8-58c376cbf878"
```
**Owner split.** ArgoCD bootstrap is **railiance-platform's** (operator
decision 2026-06-19): repo registration in ArgoCD, AppProject/app-of-apps
convention, and the agreed GitOps source layout. This task is `wait` on that
handoff. issue-core's part is to **contribute** the `Application` manifest +
workload manifests into the layout platform defines.
convention, and the agreed GitOps source layout. This handoff is complete for
the issue-core pilot; issue-core contributes workload manifests and platform owns
the tenant `Application` wrapper.
- **(railiance-platform)** Register the GitOps source repo (repository Secret +
creds); define AppProject for cluster services; publish the source-repo/path
@@ -136,16 +163,17 @@ workload manifests into the layout platform defines.
- [x] **(issue-core)** Workload manifests in `k8s/railiance/` on `main` per
platform contract (`docs/argocd-gitops.md`). Tenant `Application` lives in
`railiance-platform/argocd/applications/issue-core.application.yaml`.
- [ ] **(railiance-platform)** RAILIANCE-WP-0004-T05 live bootstrap: register
repo creds, deploy bootstrap, sync `issue-core` Application.
- [ ] Verify: `kubectl get applications -n argocd` shows `issue-core`
Synced/Healthy; ArgoCD reconciles a trivial manifest change.
- [x] **(railiance-platform)** Live bootstrap deployed; `issue-core` Application
syncs from the issue-core repo through the tenant AppProject.
- [x] Verify: `kubectl get applications -n argocd` shows `issue-core`
Synced/Healthy at revision `11a0a69`; ArgoCD reconciled the `0.2.1` image
manifest change.
## Kubernetes manifests (namespace, Deployment, Service) in GitOps source
```task
id: ISSUE-WP-0003-T03
status: progress
status: done
priority: high
state_hub_task_id: "38887dd6-0988-4ad1-bc6b-2a1b8839829f"
```
@@ -154,18 +182,18 @@ state_hub_task_id: "38887dd6-0988-4ad1-bc6b-2a1b8839829f"
- [x] `k8s/railiance/` Kustomize bundle (namespace via ArgoCD
`CreateNamespace=true`).
- [x] Deployment: registry image tag `0.2.0`; port 8765; `/healthz` probes;
- [x] Deployment: registry image tag `0.2.1`; port 8765; `/healthz` probes;
resource requests/limits; env from ExternalSecret (T04) and ConfigMap (T05).
- [x] Service: ClusterIP on **8765** as
`issue-core.issue-core.svc.cluster.local`.
- [ ] Verify: ArgoCD syncs the manifests; Pod Ready; `/healthz` 200 from a debug
pod (blocked on T01 push + T02 bootstrap + T04 secrets).
- [x] Verify: ArgoCD syncs the manifests; pod Ready; `/healthz` returned 200
from inside the cluster.
## OpenBao secret: ISSUE_CORE_API_KEY
```task
id: ISSUE-WP-0003-T04
status: wait
status: done
priority: high
state_hub_task_id: "ad52527f-6222-4c11-9284-d8a3ed3b49ad"
```
@@ -180,15 +208,15 @@ state_hub_task_id: "ad52527f-6222-4c11-9284-d8a3ed3b49ad"
- Never write the value to Git, manifests, State Hub, or logs.
- Verify: both pods resolve a non-empty key; auth round-trip (401 without,
201 with).
- Current wait reason: requires railiance-platform/OpenBao operator action to
confirm/provision the canonical path and `ClusterSecretStore`;
issue-core records only the Secret contract and non-secret verification steps.
- Done 2026-06-25: canonical OpenBao path exists, `ClusterSecretStore/openbao` is
Ready, `ExternalSecret/issue-core-runtime` is Ready, and the Kubernetes Secret
contains the two expected data keys. activity-core consumption remains in T06.
## In-cluster backend config (cluster Gitea / markitect)
```task
id: ISSUE-WP-0003-T05
status: progress
status: done
priority: medium
state_hub_task_id: "10923f1e-050d-4f3e-980e-b061fef5f33a"
```
@@ -200,14 +228,14 @@ the cluster Gitea (markitect) backend.
(`gitea-http.default.svc.cluster.local:3000`); token sentinel `__FROM_ENV__`.
- [x] `docker-entrypoint.sh` renders `~/.config/issue-tracker/backends.json`
from `BACKENDS_TEMPLATE` + `GITEA_BACKEND_TOKEN` at startup.
- [ ] Verify: a `POST /issues/` creates a real Gitea issue and returns
`issue_url` (blocked on T04 secrets + in-cluster deployment).
- [x] Verify: authenticated `POST /issues/` returned 201 and created Gitea
issue id `175` via the live service.
## Wire activity-core to the live service
```task
id: ISSUE-WP-0003-T06
status: progress
status: wait
priority: high
state_hub_task_id: "96b14cdb-364f-4eab-a80e-dd8b3859c694"
```
@@ -223,6 +251,10 @@ state_hub_task_id: "96b14cdb-364f-4eab-a80e-dd8b3859c694"
accepts `triggering_event_id` as a non-empty traceability string, so
event-driven paths can send UUIDs and cron paths can send stable keys such as
`"scheduled"`.
- [ ] activity-core runtime source still needs the live flip:
`ISSUE_CORE_URL` `8010 -> 8765` and `ISSUE_SINK_TYPE` `"null" -> "rest"`.
- [ ] activity-core worker still needs the shared `ISSUE_CORE_API_KEY` from the
approved OpenBao lane; never write the value to Git, State Hub, logs, or chat.
- Verify: an activity-core run emits a task that lands in cluster Gitea via
issue-core.
@@ -230,7 +262,7 @@ state_hub_task_id: "96b14cdb-364f-4eab-a80e-dd8b3859c694"
```task
id: ISSUE-WP-0003-T07
status: progress
status: wait
priority: medium
state_hub_task_id: "8d853b8e-cfca-441d-b817-0a29e37bd66e"
```
@@ -239,10 +271,12 @@ state_hub_task_id: "8d853b8e-cfca-441d-b817-0a29e37bd66e"
- ArgoCD Application Synced/Healthy; issue-core Pod Ready; Service reachable
cluster-internal.
- activity-core issue-core emission returns 201 and creates a Gitea issue.
- [ ] activity-core -> issue-core emission returns 201 and creates a Gitea issue
(remaining T06 handoff).
- [x] Document the GitOps runbook (image build/push, ArgoCD sync, secret
contract, smoke, activity-core handoff) in `docs/argocd-gitops.md`.
- Emit an `add_progress_event` milestone to the hub on completion.
- Emit an `add_progress_event` milestone to the hub when the activity-core
emission proof exists and this workplan can move from `blocked` to `finished`.
---