Compare commits
10 commits
7693ef8680
...
6718618568
| Author | SHA1 | Date | |
|---|---|---|---|
| 6718618568 | |||
| 54a9749616 | |||
| a691f93f16 | |||
| 8d34c6d468 | |||
| e5172611ec | |||
| 9e46004961 | |||
| 11a0a69870 | |||
| 3c66148205 | |||
| 2f40dea6a1 | |||
| 8c01f07c2d |
12 changed files with 340 additions and 93 deletions
|
|
@ -2,21 +2,12 @@
|
||||||
# Custodian Brief — issue-core
|
# Custodian Brief — issue-core
|
||||||
|
|
||||||
**Domain:** infotech
|
**Domain:** infotech
|
||||||
**Last synced:** 2026-06-23 12:26 UTC
|
**Last synced:** 2026-07-02 12:50 UTC
|
||||||
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
|
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
|
||||||
|
|
||||||
## Active Workstreams
|
## Active Workstreams
|
||||||
|
|
||||||
### Deploy issue-core as a service on railiance01 (ArgoCD GitOps pilot)
|
*(none — repo may need first-session setup)*
|
||||||
Progress: 1/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`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
## MCP Orientation (when available)
|
## MCP Orientation (when available)
|
||||||
|
|
|
||||||
29
.forgejo/workflows/ci-smoke.yaml
Normal file
29
.forgejo/workflows/ci-smoke.yaml
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Canonical CI smoke template (tier 1 routing drill).
|
||||||
|
# Copy to: .forgejo/workflows/ci-smoke.yaml in consumer repos.
|
||||||
|
name: CI Smoke
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
host-smoke:
|
||||||
|
runs-on: self-hosted
|
||||||
|
steps:
|
||||||
|
- name: Routing probe (host runner)
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
echo "repository=${GITHUB_REPOSITORY:-unknown}"
|
||||||
|
echo "sha=${GITHUB_SHA:-unknown}"
|
||||||
|
echo "runner=${RUNNER_NAME:-unknown}"
|
||||||
|
uname -a
|
||||||
|
|
||||||
|
container-smoke:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Routing probe (container label)
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
echo "container-smoke ok for ${GITHUB_REPOSITORY:-unknown}"
|
||||||
43
.forgejo/workflows/image.yaml
Normal file
43
.forgejo/workflows/image.yaml
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
name: Build and Publish Container Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- ".forgejo/workflows/image.yaml"
|
||||||
|
- "Dockerfile"
|
||||||
|
- "issue_core/**"
|
||||||
|
- "docker-entrypoint.sh"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: forgejo.coulomb.social
|
||||||
|
IMAGE_NAME: coulomb/issue-core
|
||||||
|
DOCKER_HOST: tcp://127.0.0.1:2375
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push:
|
||||||
|
runs-on: container-build
|
||||||
|
steps:
|
||||||
|
- name: Build and push image
|
||||||
|
env:
|
||||||
|
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||||
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
REF="${GITHUB_SHA:-main}"
|
||||||
|
SHORT="${REF:0:7}"
|
||||||
|
mkdir -p buildctx "${HOME}/bin"
|
||||||
|
wget -qO /tmp/repo.tar.gz \
|
||||||
|
"https://forgejo.coulomb.social/${GITHUB_REPOSITORY}/archive/${SHORT}.tar.gz"
|
||||||
|
tar xzf /tmp/repo.tar.gz -C buildctx --strip-components=1
|
||||||
|
wget -qO- https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz \
|
||||||
|
| tar xz --strip-components=1 -C "${HOME}/bin" docker/docker
|
||||||
|
export PATH="${HOME}/bin:${PATH}"
|
||||||
|
echo "${REGISTRY_TOKEN}" | docker login "${REGISTRY}" -u "${REGISTRY_USER}" --password-stdin
|
||||||
|
IMAGE="${REGISTRY}/${IMAGE_NAME}"
|
||||||
|
docker build -t "${IMAGE}:latest" -t "${IMAGE}:main-${SHORT}" buildctx
|
||||||
|
docker push "${IMAGE}:latest"
|
||||||
|
docker push "${IMAGE}:main-${SHORT}"
|
||||||
|
echo "pushed ${IMAGE}:latest and ${IMAGE}:main-${SHORT}"
|
||||||
22
Dockerfile
22
Dockerfile
|
|
@ -1,15 +1,10 @@
|
||||||
# issue-core REST ingestion service image.
|
# issue-core REST ingestion service image.
|
||||||
#
|
#
|
||||||
# Installs the published issue-core[api] package from the Coulomb Gitea PyPI
|
# Builds the checked-out issue-core[api] package and runs the FastAPI ingestion
|
||||||
# index (no sibling-checkout build context) and runs the FastAPI ingestion
|
# server on :8765. The image is published to
|
||||||
# server on :8765. Built and pushed to gitea.coulomb.social/coulomb/issue-core.
|
# gitea.coulomb.social/coulomb/issue-core.
|
||||||
FROM python:3.12-slim AS runtime
|
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 \
|
ENV PYTHONUNBUFFERED=1 \
|
||||||
PYTHONDONTWRITEBYTECODE=1 \
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
HOME=/home/app
|
HOME=/home/app
|
||||||
|
|
@ -18,10 +13,11 @@ ENV PYTHONUNBUFFERED=1 \
|
||||||
# (~/.config/issue-tracker/backends.json).
|
# (~/.config/issue-tracker/backends.json).
|
||||||
RUN useradd --create-home --home-dir /home/app --uid 10001 app
|
RUN useradd --create-home --home-dir /home/app --uid 10001 app
|
||||||
|
|
||||||
RUN pip install --no-cache-dir \
|
WORKDIR /src
|
||||||
--index-url https://pypi.org/simple \
|
COPY pyproject.toml README.md LICENSE ./
|
||||||
--extra-index-url "${GITEA_PYPI_INDEX_URL}" \
|
COPY issue_core ./issue_core
|
||||||
"issue-core[api]${ISSUE_CORE_VERSION}"
|
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
|
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
||||||
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
||||||
|
|
@ -30,4 +26,4 @@ USER app
|
||||||
EXPOSE 8765
|
EXPOSE 8765
|
||||||
|
|
||||||
# Entrypoint renders backends.json from env, then execs the server.
|
# Entrypoint renders backends.json from env, then execs the server.
|
||||||
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
||||||
|
|
@ -7,7 +7,7 @@ railiance-platform.
|
||||||
## Source layout
|
## Source layout
|
||||||
|
|
||||||
- Workload bundle: `issue-core/k8s/railiance/`
|
- 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`
|
- Container port and Service port: `8765`
|
||||||
- Cluster Service URL: `http://issue-core.issue-core.svc.cluster.local:8765`
|
- Cluster Service URL: `http://issue-core.issue-core.svc.cluster.local:8765`
|
||||||
- Tenant Application: `railiance-platform/argocd/applications/issue-core.application.yaml`
|
- Tenant Application: `railiance-platform/argocd/applications/issue-core.application.yaml`
|
||||||
|
|
@ -18,31 +18,31 @@ therefore intentionally not duplicated in this bundle.
|
||||||
|
|
||||||
## Platform gates
|
## Platform gates
|
||||||
|
|
||||||
The following pieces are owned by railiance-platform before the workload can
|
The following pieces are owned by railiance-platform for the live pilot and for
|
||||||
be fully reconciled:
|
any future cluster replay:
|
||||||
|
|
||||||
- ArgoCD repository credentials and the project/app-of-apps convention.
|
- ArgoCD repository credentials and the project/app-of-apps convention.
|
||||||
- The `issue-core` ArgoCD `Application`.
|
- The `issue-core` ArgoCD `Application`.
|
||||||
- External Secrets Operator and a `ClusterSecretStore` named `openbao`.
|
- External Secrets Operator and a `ClusterSecretStore` named `openbao`.
|
||||||
- OpenBao entries for the issue-core runtime Secret.
|
- OpenBao entries for the issue-core runtime Secret.
|
||||||
|
|
||||||
Until those gates exist, `kubectl kustomize k8s/railiance` can render locally,
|
For the 2026-06-25 live deployment, these gates were satisfied and the
|
||||||
but the live `ExternalSecret` and `Deployment` are expected to wait.
|
`issue-core` Application reached Synced/Healthy with image `0.2.1`.
|
||||||
|
|
||||||
## Secret contract
|
## Secret contract
|
||||||
|
|
||||||
Kubernetes Secret name: `issue-core-runtime`
|
Kubernetes Secret name: `issue-core-runtime`
|
||||||
|
|
||||||
Current issue-core manifest path, pending railiance-platform confirmation:
|
Current issue-core manifest path:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
platform/workloads/issue-core/issue-core/issue-core-runtime
|
platform/workloads/issue-core/issue-core/issue-core-runtime
|
||||||
```
|
```
|
||||||
|
|
||||||
Credential route catalog id `issue-core-ingestion-api-key` is owned by
|
Credential custody is owned by railiance-platform/OpenBao. For agents, first
|
||||||
railiance-platform/OpenBao and is still marked draft/path TBD in the local
|
use the non-secret route catalog entry `activity-core-issue-sink` to confirm
|
||||||
ops-warden catalog reviewed 2026-06-18. Confirm the canonical path before
|
the activity-core + issue-core pairing, and never request the value from
|
||||||
provisioning the live Secret.
|
ops-warden.
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
|
|
||||||
|
|
@ -56,12 +56,12 @@ HTTP status codes, and created issue URLs.
|
||||||
|
|
||||||
## Build and publish
|
## Build and publish
|
||||||
|
|
||||||
Use the published package as the image input. For a reproducible release image,
|
Build the checked-out source tree and publish a registry tag that ArgoCD can
|
||||||
pin the package version to the image tag:
|
pull:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build --build-arg ISSUE_CORE_VERSION="==0.2.0" -t 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.0
|
docker push gitea.coulomb.social/coulomb/issue-core:0.2.1
|
||||||
```
|
```
|
||||||
|
|
||||||
The Coulomb Gitea package is public-pullable for this image, so the workload
|
The Coulomb Gitea package is public-pullable for this image, so the workload
|
||||||
|
|
@ -137,7 +137,7 @@ spec:
|
||||||
command: ["/bin/sh", "-ceu"]
|
command: ["/bin/sh", "-ceu"]
|
||||||
args:
|
args:
|
||||||
- |
|
- |
|
||||||
curl -fsS -X POST "http://issue-core:8765/issues/" -H "Authorization: Bearer ${ISSUE_CORE_API_KEY}" -H "Content-Type: application/json" --data '{"title":"issue-core railiance01 smoke","description":"GitOps smoke created by the issue-core deployment runbook.","target_repo":"coulomb/markitect_project","priority":"low","labels":["smoke","issue-core"],"source_type":"rule","source_id":"issue-core-gitops-smoke","triggering_event_id":"scheduled","activity_definition_id":"issue-core-gitops-smoke"}'
|
curl -fsS -X POST "http://issue-core:8765/issues/" -H "Authorization: Bearer ${ISSUE_CORE_API_KEY}" -H "Content-Type: application/json" --data '{"title":"issue-core railiance01 smoke","description":"GitOps smoke created by the issue-core deployment runbook.","target_repo":"coulomb/markitect-main","priority":"low","labels":["smoke","issue-core"],"source_type":"rule","source_id":"issue-core-gitops-smoke","triggering_event_id":"scheduled","activity_definition_id":"issue-core-gitops-smoke"}'
|
||||||
YAML
|
YAML
|
||||||
kubectl -n issue-core wait --for=condition=complete job/issue-core-smoke --timeout=90s
|
kubectl -n issue-core wait --for=condition=complete job/issue-core-smoke --timeout=90s
|
||||||
kubectl -n issue-core logs job/issue-core-smoke
|
kubectl -n issue-core logs job/issue-core-smoke
|
||||||
|
|
|
||||||
82
integration/gitea-backend.integration.yaml
Normal file
82
integration/gitea-backend.integration.yaml
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
schema_version: open-reuse.integration.v0.1
|
||||||
|
id: issue-core-gitea
|
||||||
|
name: issue-core Gitea Backend
|
||||||
|
description: >
|
||||||
|
Pluggable remote backend that maps the issue-core unified task model onto the
|
||||||
|
Gitea issues API for cross-repo task landing and synchronization.
|
||||||
|
status: registered
|
||||||
|
owner: issue-core
|
||||||
|
|
||||||
|
local:
|
||||||
|
repo: issue-core
|
||||||
|
path: integration/gitea-backend.integration.yaml
|
||||||
|
system: issue-core
|
||||||
|
|
||||||
|
upstream:
|
||||||
|
name: Gitea
|
||||||
|
project_url: https://github.com/go-gitea/gitea
|
||||||
|
homepage: https://about.gitea.com/
|
||||||
|
version_policy: gitea-api-v1
|
||||||
|
monitor:
|
||||||
|
releases: true
|
||||||
|
tags: true
|
||||||
|
security_advisories: true
|
||||||
|
license_changes: true
|
||||||
|
|
||||||
|
reuse:
|
||||||
|
primary_reuse_mode: adapter
|
||||||
|
secondary_reuse_modes:
|
||||||
|
- plugin
|
||||||
|
risk_level: medium
|
||||||
|
rationale: >
|
||||||
|
Gitea REST API is wrapped behind the RemoteBackend interface; local task
|
||||||
|
lifecycle semantics remain stable across backend swaps.
|
||||||
|
|
||||||
|
boundary:
|
||||||
|
type: adapter
|
||||||
|
local_adapter: issue_core.backends.gitea.backend.GiteaBackend
|
||||||
|
local_interface: issue_core.core.interfaces.RemoteBackend
|
||||||
|
reused_surface: Gitea /api/v1 issues, labels, milestones, comments
|
||||||
|
contracts:
|
||||||
|
- issue-core.backend.v1
|
||||||
|
fragility_points:
|
||||||
|
- Gitea API field changes
|
||||||
|
- issue state mapping differences
|
||||||
|
- pagination and rate-limit behavior
|
||||||
|
- authentication token scopes
|
||||||
|
|
||||||
|
validation:
|
||||||
|
harness: python3 -m pytest tests/test_gitea_backend.py
|
||||||
|
skip_without_runtime: true
|
||||||
|
checks:
|
||||||
|
- API client request shaping
|
||||||
|
- issue state mapping
|
||||||
|
- error handling for rate limits
|
||||||
|
policy: required-before-update
|
||||||
|
|
||||||
|
update_policy:
|
||||||
|
default_action: require-maintainer-review
|
||||||
|
auto_eligible: false
|
||||||
|
|
||||||
|
risks:
|
||||||
|
sensitivity:
|
||||||
|
- Gitea API breaking changes
|
||||||
|
- authentication model changes
|
||||||
|
- rate-limit policy changes
|
||||||
|
- license changes
|
||||||
|
escalation_triggers:
|
||||||
|
- validation failure
|
||||||
|
- Gitea major release
|
||||||
|
- production sync errors
|
||||||
|
|
||||||
|
maintenance:
|
||||||
|
maintainers:
|
||||||
|
- issue-core
|
||||||
|
escalation_conditions:
|
||||||
|
- Gitea API compatibility failure
|
||||||
|
- validation failure
|
||||||
|
- production backend sync regression
|
||||||
|
|
||||||
|
audit:
|
||||||
|
registered_at: "2026-06-24"
|
||||||
|
registered_by: open-reuse
|
||||||
|
|
@ -19,6 +19,6 @@ Supported Backends:
|
||||||
- Future: GitHub, GitLab, JIRA, Redmine
|
- Future: GitHub, GitLab, JIRA, Redmine
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "0.2.0"
|
__version__ = "0.2.1"
|
||||||
__author__ = "Coulomb / MarkiTect Project"
|
__author__ = "Coulomb / MarkiTect Project"
|
||||||
__description__ = "Authoritative task lifecycle manager with plugin architecture"
|
__description__ = "Authoritative task lifecycle manager with plugin architecture"
|
||||||
|
|
|
||||||
|
|
@ -195,10 +195,20 @@ class GiteaBackend(RemoteBackend, SyncableBackend):
|
||||||
if issue.milestone:
|
if issue.milestone:
|
||||||
data['milestone'] = int(issue.milestone.backend_id) if issue.milestone.backend_id else None
|
data['milestone'] = int(issue.milestone.backend_id) if issue.milestone.backend_id else None
|
||||||
|
|
||||||
# Convert labels
|
# Gitea expects numeric label IDs on issue create/update. Name-only
|
||||||
if issue.labels:
|
# labels are preserved in issue-core metadata but omitted from the API
|
||||||
data['labels'] = [label.name for label in issue.labels]
|
# payload until a label-resolution step exists.
|
||||||
|
label_ids = []
|
||||||
|
for label in issue.labels:
|
||||||
|
if not label.backend_id:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
label_ids.append(int(label.backend_id))
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
continue
|
||||||
|
if label_ids:
|
||||||
|
data['labels'] = label_ids
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
# Issue CRUD Operations
|
# Issue CRUD Operations
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ data:
|
||||||
"type": "gitea",
|
"type": "gitea",
|
||||||
"base_url": "http://gitea-http.default.svc.cluster.local:3000",
|
"base_url": "http://gitea-http.default.svc.cluster.local:3000",
|
||||||
"owner": "coulomb",
|
"owner": "coulomb",
|
||||||
"repo": "markitect_project",
|
"repo": "markitect-main",
|
||||||
"token": "__FROM_ENV__"
|
"token": "__FROM_ENV__"
|
||||||
},
|
},
|
||||||
"default": "markitect"
|
"default": "markitect"
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ spec:
|
||||||
# docs). Add imagePullSecrets: [{name: gitea-registry}] if it becomes private.
|
# docs). Add imagePullSecrets: [{name: gitea-registry}] if it becomes private.
|
||||||
containers:
|
containers:
|
||||||
- name: issue-core
|
- 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
|
imagePullPolicy: IfNotPresent
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
|
|
@ -67,5 +67,6 @@ spec:
|
||||||
allowPrivilegeEscalation: false
|
allowPrivilegeEscalation: false
|
||||||
readOnlyRootFilesystem: false
|
readOnlyRootFilesystem: false
|
||||||
runAsNonRoot: true
|
runAsNonRoot: true
|
||||||
|
runAsUser: 10001
|
||||||
capabilities:
|
capabilities:
|
||||||
drop: ["ALL"]
|
drop: ["ALL"]
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,10 @@ These tests ensure the Gitea backend works correctly with the API.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import json
|
import json
|
||||||
|
from datetime import datetime, timezone
|
||||||
from unittest.mock import Mock, patch, MagicMock
|
from unittest.mock import Mock, patch, MagicMock
|
||||||
from issue_core.backends.gitea.backend import GiteaBackend, GiteaAPIError
|
from issue_core.backends.gitea.backend import GiteaBackend, GiteaAPIError
|
||||||
|
from issue_core.core.models import Issue, IssueState, Label
|
||||||
|
|
||||||
|
|
||||||
class TestGiteaBackend:
|
class TestGiteaBackend:
|
||||||
|
|
@ -96,6 +98,29 @@ class TestGiteaBackend:
|
||||||
called_url = mock_request.call_args[1]['url'] if 'url' in mock_request.call_args[1] else mock_request.call_args[0][1]
|
called_url = mock_request.call_args[1]['url'] if 'url' in mock_request.call_args[1] else mock_request.call_args[0][1]
|
||||||
assert called_url == 'https://git.example.com/api/v1/repos/owner/repo'
|
assert called_url == 'https://git.example.com/api/v1/repos/owner/repo'
|
||||||
|
|
||||||
|
def test_gitea_payload_omits_name_only_labels(self):
|
||||||
|
"""Gitea issue payloads only include numeric label IDs."""
|
||||||
|
now = datetime.now(timezone.utc)
|
||||||
|
issue = Issue(
|
||||||
|
id="",
|
||||||
|
number=0,
|
||||||
|
title="Test issue",
|
||||||
|
description="Test description",
|
||||||
|
state=IssueState.OPEN,
|
||||||
|
created_at=now,
|
||||||
|
updated_at=now,
|
||||||
|
labels=[
|
||||||
|
Label(name="priority:low"),
|
||||||
|
Label(name="source:rule", backend_id="not-a-number"),
|
||||||
|
Label(name="existing", backend_id="42"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
payload = self.backend._unified_issue_to_gitea(issue)
|
||||||
|
|
||||||
|
assert payload["labels"] == [42]
|
||||||
|
assert payload["title"] == "Test issue"
|
||||||
|
|
||||||
@patch('issue_core.backends.gitea.backend.requests.Session')
|
@patch('issue_core.backends.gitea.backend.requests.Session')
|
||||||
def test_test_connection_success(self, mock_session_class):
|
def test_test_connection_success(self, mock_session_class):
|
||||||
"""Test test_connection method works correctly."""
|
"""Test test_connection method works correctly."""
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ type: workplan
|
||||||
title: "Deploy issue-core as a service on railiance01 (ArgoCD GitOps pilot)"
|
title: "Deploy issue-core as a service on railiance01 (ArgoCD GitOps pilot)"
|
||||||
domain: infotech
|
domain: infotech
|
||||||
repo: issue-core
|
repo: issue-core
|
||||||
status: active
|
status: finished
|
||||||
owner: claude
|
owner: claude
|
||||||
topic_slug: custodian
|
topic_slug: custodian
|
||||||
created: "2026-06-19"
|
created: "2026-06-19"
|
||||||
updated: "2026-06-23"
|
updated: "2026-06-30"
|
||||||
state_hub_workstream_id: "896ace77-21b3-450b-8fb7-254aefc8c570"
|
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
|
`issue-core` is the authoritative task-lifecycle manager and the REST ingestion
|
||||||
target for activity-core's `IssueSink`. Deployment artifacts are on `main`
|
target for activity-core's `IssueSink`. Deployment artifacts are on `main`
|
||||||
(`Dockerfile`, `docker-entrypoint.sh`, `k8s/railiance/`); image
|
(`Dockerfile`, `docker-entrypoint.sh`, `k8s/railiance/`); image
|
||||||
`gitea.coulomb.social/coulomb/issue-core:0.2.0` is built, pushed, and
|
`gitea.coulomb.social/coulomb/issue-core:0.2.1` is built, pushed, and
|
||||||
pullable. The railiance01 cluster still has no `issue-core` workload until
|
pullable. The railiance01 cluster now reconciles `issue-core` through ArgoCD;
|
||||||
T02 live ArgoCD bootstrap (RAILIANCE-WP-0004-T05) and T04 OpenBao secrets land.
|
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
|
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
|
railiance01 **via ArgoCD GitOps** — making issue-core the cluster's first
|
||||||
declarative Application and turning on the idle GitOps capability.
|
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
|
- **Deployment artifacts in-repo:** `Dockerfile`, `docker-entrypoint.sh`, and
|
||||||
`k8s/railiance/` (Kustomize: ExternalSecret, ConfigMap, Deployment, Service).
|
`k8s/railiance/` (Kustomize: ExternalSecret, ConfigMap, Deployment, Service).
|
||||||
Image builds locally; `docker run` + `GET /healthz` returns 200. Image pushed
|
Image builds locally; `docker run` + `GET /healthz` returns 200. Image pushed
|
||||||
and pullable as `gitea.coulomb.social/coulomb/issue-core:0.2.0` (digest
|
and pullable as `gitea.coulomb.social/coulomb/issue-core:0.2.1` (digest
|
||||||
`sha256:153fbe43…`). `coulomb` org packages are public — no `imagePullSecret`
|
`sha256:729c0e56…`). `coulomb` org packages are public — no `imagePullSecret`
|
||||||
required per `railiance-forge/docs/gitea-container-registry.md`.
|
required per `railiance-forge/docs/gitea-container-registry.md`.
|
||||||
- **Dockerfile fix (2026-06-19):** build arg renamed `GITEA_PYPI_INDEX_URL` —
|
- **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
|
`ARG PIP_INDEX_URL` leaked into the build env and pip used Gitea as the sole
|
||||||
index, so dependencies like `click` were not found.
|
index, so dependencies like `click` were not found.
|
||||||
- **railiance01 cluster:** no `issue-core` namespace; no issue-core
|
- **railiance01 cluster:** `issue-core` namespace, Service, ExternalSecret,
|
||||||
Deployment/Service/Pod in any namespace.
|
Secret, and Deployment are present. ArgoCD reports the `issue-core` Application
|
||||||
- **Dangling reference:** `activity-core/k8s/railiance/20-runtime.yaml` sets
|
Synced/Healthy at revision `11a0a69`; pod is Ready on image `0.2.1`.
|
||||||
`ISSUE_CORE_URL: http://issue-core.issue-core.svc.cluster.local:8010` — a
|
- **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.
|
||||||
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.
|
|
||||||
- **Packaging precursor is done:** `ISSUE-WP-0002` published
|
- **Packaging precursor is done:** `ISSUE-WP-0002` published
|
||||||
`issue-core==0.2.0` to the Coulomb Gitea PyPI index.
|
`issue-core==0.2.0` to the Coulomb Gitea PyPI index. The live `0.2.1` image
|
||||||
- **ArgoCD is installed but unused:** all 7 components healthy (~290d), but
|
was built from the committed source tree as a deployment hotfix.
|
||||||
**0 Applications, 0 ApplicationSets, 0 registered git repos**, only the stock
|
- **ArgoCD is active for the pilot:** railiance-platform owns the bootstrap and tenant AppProject; `issue-core` is Synced/Healthy as the pilot workload.
|
||||||
`default` AppProject. No `kind: Application` manifests exist in any infra repo.
|
|
||||||
- **Existing deploy pattern is imperative** (the path we are *replacing* for
|
- **Existing deploy pattern is imperative** (the path we are *replacing* for
|
||||||
this service): local `docker build` → `k3s ctr images import` (side-load, no
|
this service): local `docker build` → `k3s ctr images import` (side-load, no
|
||||||
registry) → `rsync` manifests → `kubectl apply` (see
|
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;
|
traceability string. Event-driven activity-core paths can still send UUIDs;
|
||||||
scheduled/cron paths may now send a stable key such as `scheduled`.
|
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
|
## Decisions
|
||||||
|
|
||||||
- **Deployment method = ArgoCD GitOps** (operator decision 2026-06-19).
|
- **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.
|
**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
|
- [x] Add `Dockerfile` building the checked-out `issue-core[api]` source.
|
||||||
PyPI index (with explicit PyPI primary index). Entrypoint renders
|
Entrypoint renders `backends.json` then `issue serve --host 0.0.0.0 --port 8765`.
|
||||||
`backends.json` then `issue serve --host 0.0.0.0 --port 8765`.
|
|
||||||
- [x] Local build succeeds; `docker run` + `GET /healthz` returns 200.
|
- [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.
|
succeeds.
|
||||||
- [x] No cluster pull secret needed (`coulomb` org packages are public).
|
- [x] No cluster pull secret needed (`coulomb` org packages are public).
|
||||||
- [ ] `POST /issues/` smoke against a running deployment (deferred to T03/T04
|
- [x] `POST /issues/` smoke against a running deployment returned 201.
|
||||||
cluster verification).
|
|
||||||
|
|
||||||
## ArgoCD bootstrap (railiance-platform dependency) + issue-core Application
|
## ArgoCD bootstrap (railiance-platform dependency) + issue-core Application
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: ISSUE-WP-0003-T02
|
id: ISSUE-WP-0003-T02
|
||||||
status: wait
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "9b199b1d-d3c0-4621-b8f8-58c376cbf878"
|
state_hub_task_id: "9b199b1d-d3c0-4621-b8f8-58c376cbf878"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Owner split.** ArgoCD bootstrap is **railiance-platform's** (operator
|
**Owner split.** ArgoCD bootstrap is **railiance-platform's** (operator
|
||||||
decision 2026-06-19): repo registration in ArgoCD, AppProject/app-of-apps
|
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
|
convention, and the agreed GitOps source layout. This handoff is complete for
|
||||||
handoff. issue-core's part is to **contribute** the `Application` manifest +
|
the issue-core pilot; issue-core contributes workload manifests and platform owns
|
||||||
workload manifests into the layout platform defines.
|
the tenant `Application` wrapper.
|
||||||
|
|
||||||
- **(railiance-platform)** Register the GitOps source repo (repository Secret +
|
- **(railiance-platform)** Register the GitOps source repo (repository Secret +
|
||||||
creds); define AppProject for cluster services; publish the source-repo/path
|
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
|
- [x] **(issue-core)** Workload manifests in `k8s/railiance/` on `main` per
|
||||||
platform contract (`docs/argocd-gitops.md`). Tenant `Application` lives in
|
platform contract (`docs/argocd-gitops.md`). Tenant `Application` lives in
|
||||||
`railiance-platform/argocd/applications/issue-core.application.yaml`.
|
`railiance-platform/argocd/applications/issue-core.application.yaml`.
|
||||||
- [ ] **(railiance-platform)** RAILIANCE-WP-0004-T05 live bootstrap: register
|
- [x] **(railiance-platform)** Live bootstrap deployed; `issue-core` Application
|
||||||
repo creds, deploy bootstrap, sync `issue-core` Application.
|
syncs from the issue-core repo through the tenant AppProject.
|
||||||
- [ ] Verify: `kubectl get applications -n argocd` shows `issue-core`
|
- [x] Verify: `kubectl get applications -n argocd` shows `issue-core`
|
||||||
Synced/Healthy; ArgoCD reconciles a trivial manifest change.
|
Synced/Healthy at revision `11a0a69`; ArgoCD reconciled the `0.2.1` image
|
||||||
|
manifest change.
|
||||||
|
|
||||||
## Kubernetes manifests (namespace, Deployment, Service) in GitOps source
|
## Kubernetes manifests (namespace, Deployment, Service) in GitOps source
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: ISSUE-WP-0003-T03
|
id: ISSUE-WP-0003-T03
|
||||||
status: progress
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "38887dd6-0988-4ad1-bc6b-2a1b8839829f"
|
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
|
- [x] `k8s/railiance/` Kustomize bundle (namespace via ArgoCD
|
||||||
`CreateNamespace=true`).
|
`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).
|
resource requests/limits; env from ExternalSecret (T04) and ConfigMap (T05).
|
||||||
- [x] Service: ClusterIP on **8765** as
|
- [x] Service: ClusterIP on **8765** as
|
||||||
`issue-core.issue-core.svc.cluster.local`.
|
`issue-core.issue-core.svc.cluster.local`.
|
||||||
- [ ] Verify: ArgoCD syncs the manifests; Pod Ready; `/healthz` 200 from a debug
|
- [x] Verify: ArgoCD syncs the manifests; pod Ready; `/healthz` returned 200
|
||||||
pod (blocked on T01 push + T02 bootstrap + T04 secrets).
|
from inside the cluster.
|
||||||
|
|
||||||
## OpenBao secret: ISSUE_CORE_API_KEY
|
## OpenBao secret: ISSUE_CORE_API_KEY
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: ISSUE-WP-0003-T04
|
id: ISSUE-WP-0003-T04
|
||||||
status: wait
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "ad52527f-6222-4c11-9284-d8a3ed3b49ad"
|
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.
|
- Never write the value to Git, manifests, State Hub, or logs.
|
||||||
- Verify: both pods resolve a non-empty key; auth round-trip (401 without,
|
- Verify: both pods resolve a non-empty key; auth round-trip (401 without,
|
||||||
201 with).
|
201 with).
|
||||||
- Current wait reason: requires railiance-platform/OpenBao operator action to
|
- Done 2026-06-25: canonical OpenBao path exists, `ClusterSecretStore/openbao` is
|
||||||
confirm/provision the canonical path and `ClusterSecretStore`;
|
Ready, `ExternalSecret/issue-core-runtime` is Ready, and the Kubernetes Secret
|
||||||
issue-core records only the Secret contract and non-secret verification steps.
|
contains the two expected data keys. activity-core consumption remains in T06.
|
||||||
|
|
||||||
## In-cluster backend config (cluster Gitea / markitect)
|
## In-cluster backend config (cluster Gitea / markitect)
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: ISSUE-WP-0003-T05
|
id: ISSUE-WP-0003-T05
|
||||||
status: progress
|
status: done
|
||||||
priority: medium
|
priority: medium
|
||||||
state_hub_task_id: "10923f1e-050d-4f3e-980e-b061fef5f33a"
|
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__`.
|
(`gitea-http.default.svc.cluster.local:3000`); token sentinel `__FROM_ENV__`.
|
||||||
- [x] `docker-entrypoint.sh` renders `~/.config/issue-tracker/backends.json`
|
- [x] `docker-entrypoint.sh` renders `~/.config/issue-tracker/backends.json`
|
||||||
from `BACKENDS_TEMPLATE` + `GITEA_BACKEND_TOKEN` at startup.
|
from `BACKENDS_TEMPLATE` + `GITEA_BACKEND_TOKEN` at startup.
|
||||||
- [ ] Verify: a `POST /issues/` creates a real Gitea issue and returns
|
- [x] Verify: authenticated `POST /issues/` returned 201 and created Gitea
|
||||||
`issue_url` (blocked on T04 secrets + in-cluster deployment).
|
issue id `175` via the live service.
|
||||||
|
|
||||||
## Wire activity-core to the live service
|
## Wire activity-core to the live service
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: ISSUE-WP-0003-T06
|
id: ISSUE-WP-0003-T06
|
||||||
status: progress
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "96b14cdb-364f-4eab-a80e-dd8b3859c694"
|
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
|
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
|
event-driven paths can send UUIDs and cron paths can send stable keys such as
|
||||||
`"scheduled"`.
|
`"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
|
- Verify: an activity-core run emits a task that lands in cluster Gitea via
|
||||||
issue-core.
|
issue-core.
|
||||||
|
|
||||||
|
|
@ -230,7 +262,7 @@ state_hub_task_id: "96b14cdb-364f-4eab-a80e-dd8b3859c694"
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: ISSUE-WP-0003-T07
|
id: ISSUE-WP-0003-T07
|
||||||
status: progress
|
status: done
|
||||||
priority: medium
|
priority: medium
|
||||||
state_hub_task_id: "8d853b8e-cfca-441d-b817-0a29e37bd66e"
|
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
|
- ArgoCD Application Synced/Healthy; issue-core Pod Ready; Service reachable
|
||||||
cluster-internal.
|
cluster-internal.
|
||||||
- activity-core → issue-core emission returns 201 and creates a Gitea issue.
|
- [x] activity-core -> issue-core emission returns 201 and creates a Gitea issue
|
||||||
|
(2026-07-02: Gitea issue `176` via the live sink path — see completion note).
|
||||||
- [x] Document the GitOps runbook (image build/push, ArgoCD sync, secret
|
- [x] Document the GitOps runbook (image build/push, ArgoCD sync, secret
|
||||||
contract, smoke, activity-core handoff) in `docs/argocd-gitops.md`.
|
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`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -255,3 +289,39 @@ state_hub_task_id: "8d853b8e-cfca-441d-b817-0a29e37bd66e"
|
||||||
- `activity-core/k8s/railiance/README.md` — the imperative pattern being
|
- `activity-core/k8s/railiance/README.md` — the imperative pattern being
|
||||||
superseded for this service.
|
superseded for this service.
|
||||||
- `~/ops-warden/wiki/playbooks/activity-core-issue-sink.md` — key routing.
|
- `~/ops-warden/wiki/playbooks/activity-core-issue-sink.md` — key routing.
|
||||||
|
|
||||||
|
|
||||||
|
## Completion 2026-07-02 — live emission proven, topology corrected
|
||||||
|
|
||||||
|
**Topology correction:** this workplan's "railiance01 cluster" is actually the
|
||||||
|
CoulombCore k3s cluster (92.205.130.254, reached via the workstation
|
||||||
|
kubeconfig tunnel `127.0.0.1:16443`). The real railiance01 (92.205.62.239)
|
||||||
|
hosts activity-core and has no issue-core namespace. The in-cluster
|
||||||
|
`issue-core.issue-core.svc.cluster.local` URL that T06 originally assumed was
|
||||||
|
therefore never resolvable from activity-core.
|
||||||
|
|
||||||
|
**Cross-machine lane built (2026-07-02):**
|
||||||
|
- ops-bridge gained an optional `remote_host` forward destination
|
||||||
|
(ops-bridge commit) enabling tunnels to k3s ClusterIPs.
|
||||||
|
- Tunnels: `issue-core-coulombcore` (workstation `127.0.0.1:18765` ->
|
||||||
|
CoulombCore ClusterIP `10.43.103.154:8765`, health-checked on `/healthz`)
|
||||||
|
and `issue-core-railiance01` (railiance01 `127.0.0.1:18765` -> workstation).
|
||||||
|
- activity-core commit `a1e2a42`: new `actcore-issue-core-bridge`
|
||||||
|
hostNetwork proxy (host port 18081 -> node-local 18765) cloned from the
|
||||||
|
state-hub-bridge pattern, `ISSUE_CORE_URL` ->
|
||||||
|
`http://actcore-issue-core-bridge.activity-core.svc.cluster.local:8765`,
|
||||||
|
`ISSUE_SINK_TYPE` -> `rest`.
|
||||||
|
- `ISSUE_CORE_API_KEY` merged into railiance01's `actcore-runtime-secret` by
|
||||||
|
the operator via a stdin-only pipe from the approved OpenBao lane
|
||||||
|
(`CCR-2026-0002`, activated the same day).
|
||||||
|
|
||||||
|
**Emission proof:** from inside the restarted actcore-worker, the real
|
||||||
|
`IssueCoreRestSink` emitted a labeled smoke TaskSpec and received
|
||||||
|
`TaskRef(external_id='176', backend='gitea')` — Gitea issue `176` in
|
||||||
|
`coulomb/markitect-main` (default backend). Auth, bridge, tunnels, issue-core
|
||||||
|
validation, and Gitea creation all exercised on the production path.
|
||||||
|
|
||||||
|
**Contract note for emitters:** `POST /issues/` requires `target_repo` and
|
||||||
|
`activity_definition_id` (422 otherwise). activity-core `TaskSpec` defaults
|
||||||
|
(`target_repo=None`, `activity_definition_id=""`) will be rejected — rule and
|
||||||
|
instruction emitters must populate both.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue