Compare commits

...

10 commits

Author SHA1 Message Date
34c6492013 Add Forgejo CI smoke and image workflow (tier 3 T04)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Container Image / build-and-push (push) Successful in 1m12s
2026-07-06 17:11:17 +02:00
6e3e7e6176 Include ranked suggestions in daily triage digest (STATE-WP-0061).
Expose State Hub ranked_suggestions from /state/summary in the
daily_triage_digest resolver so WSJF triage can prioritize gated needs.
2026-07-06 10:52:52 +02:00
d7d7c966fa chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-03:
  - update .custodian-brief.md for activity-core
2026-07-03 19:22:06 +02:00
f36af682e4 Reevaluate blocked workplans WP-0008/0009/0010/0015
Unblock lifecycle statuses after daily triage trust evidence closed
(06-28 through 07-03 clean scheduled runs). Finish WP-0010, return
WP-0008/0009/0015 to active with accurate wait reasons, and document
the scheduled-wait vs hard-blocker distinction.
2026-07-03 19:19:52 +02:00
3bbc122ae7 chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-03:
  - update .custodian-brief.md for activity-core
2026-07-03 18:28:12 +02:00
a1e2a426b9 ISSUE-WP-0003-T06: issue-core REST sink via actcore-issue-core-bridge (node-local tunnel 18765)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 14:20:12 +02:00
9113206974 chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-02:
  - update .custodian-brief.md for activity-core
2026-07-02 11:55:47 +02:00
79fd3406a3 ACTIVITY-WP-0016: finished
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 11:55:07 +02:00
ef9a1a76c2 chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-02:
  - update .custodian-brief.md for activity-core
2026-07-02 11:54:43 +02:00
0da655979d ACTIVITY-WP-0016: T05 done via live railiance01 proof, T01 cancelled (evidence unrecoverable)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 11:54:04 +02:00
11 changed files with 299 additions and 38 deletions

View file

@ -2,19 +2,11 @@
# Custodian Brief — activity-core
**Domain:** infotech
**Last synced:** 2026-07-02 00:19 UTC
**Last synced:** 2026-07-03 17:22 UTC
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
## Active Workstreams
### LLM Output Robustness & The Producer Trust Boundary
Progress: 8/10 done | workstream_id: `4ef0d53b-1777-41ae-80c6-1b69fdb34726`
**Open tasks:**
- ! Reproduce & Root-Cause The Failure `74fd16a5`
*(wait: Local analysis complete: mechanism is the unbounded ~1-per-workstream recommendation list (16 active workstreams; break at char 5268 ~rank 8-9); both first attempt and retry failed. Exact token + finish_reason are unrecoverable from activity-core (complete() drops finish_reason; report cap 4000 < 5268; log cap 2000). Remaining: pull llm-connect producer-side logs on railiance01 (cluster/operator-owned). Does NOT block T02/T03 mitigation is identical regardless.)*
- ► Tests + Calibration Re-Entry `c881500b`
### Adopt State Hub Beachhead Endpoint
Progress: 0/2 done | workstream_id: `bbc07f9e-9323-4b2b-b556-c33b37d0b228`
@ -22,19 +14,10 @@ Progress: 0/2 done | workstream_id: `bbc07f9e-9323-4b2b-b556-c33b37d0b228`
- ! Point STATE_HUB_URL at the beachhead `76b6132d`
- ! Retire the bespoke actcore-state-hub-bridge proxy `526c2129`
### Daily Triage LLM Reconciliation And Evidence
Progress: 2/5 done | workstream_id: `f2c73ac6-13f0-4005-82cc-76c7c9f9c8b9`
**Open tasks:**
- ! Run Daily Triage Fixture Smoke `10e0df77`
- ! Collect Three Clean Scheduled Runs `dc6b9482`
- ! Close Handoff State `ecc57e21`
### Intent gap closure
Progress: 4/6 done | workstream_id: `d64cfbba-6da7-4737-afb9-866afa0e9cda`
Progress: 5/6 done | workstream_id: `d64cfbba-6da7-4737-afb9-866afa0e9cda`
**Open tasks:**
- ! Close Daily Triage Scheduled-Run Trust Gap `7012e4fd`
- ! Promote Issue-Core Task Emission Safely `3854677b`
### Weekly Coding Retrospection schedule (Saturday evenings)

View file

@ -0,0 +1,27 @@
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}"

View file

@ -0,0 +1,50 @@
name: Build and Publish Container Image
on:
push:
branches:
- main
paths:
- ".forgejo/workflows/image.yaml"
- "Dockerfile"
- "src/**"
- "migrations/**"
- "scripts/**"
- "activity-definitions/**"
- "event-types/**"
- "tasks/**"
- "pyproject.toml"
- "uv.lock"
- "alembic.ini"
workflow_dispatch:
env:
REGISTRY: forgejo.coulomb.social
IMAGE_NAME: coulomb/activity-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}"

View file

@ -14,8 +14,8 @@ data:
LLM_CONNECT_URL: http://llm-connect.activity-core.svc.cluster.local:8080
LLM_CONNECT_TIMEOUT_SECONDS: "300"
REPO_SCOPING_URL: http://repo-scoping.repo-scoping.svc.cluster.local:8020
ISSUE_CORE_URL: http://issue-core.issue-core.svc.cluster.local:8010
ISSUE_SINK_TYPE: "null"
ISSUE_CORE_URL: http://actcore-issue-core-bridge.activity-core.svc.cluster.local:8765
ISSUE_SINK_TYPE: "rest"
ACTIVITY_DEFINITION_DIRS: /etc/activity-core/external-definitions
OPS_INVENTORY_PATH: /etc/activity-core/ops/service-inventory.yml
INTER_HUB_URL: ""
@ -643,6 +643,117 @@ spec:
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
apiVersion: v1
kind: Service
metadata:
name: actcore-issue-core-bridge
namespace: activity-core
labels:
app.kubernetes.io/name: actcore-issue-core-bridge
app.kubernetes.io/part-of: activity-core
spec:
selector:
app.kubernetes.io/name: actcore-issue-core-bridge
ports:
- name: http
port: 8765
targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: actcore-issue-core-bridge
namespace: activity-core
labels:
app.kubernetes.io/name: actcore-issue-core-bridge
app.kubernetes.io/part-of: activity-core
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: actcore-issue-core-bridge
template:
metadata:
labels:
app.kubernetes.io/name: actcore-issue-core-bridge
app.kubernetes.io/part-of: activity-core
spec:
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
containers:
- name: proxy
image: activity-core:railiance01-prod
imagePullPolicy: Never
ports:
- name: http
containerPort: 18081
command:
- python
- -c
- |
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
TARGET = "http://127.0.0.1:18765"
HOP_HEADERS = {"connection", "host", "keep-alive", "proxy-authenticate",
"proxy-authorization", "te", "trailers",
"transfer-encoding", "upgrade"}
class Proxy(BaseHTTPRequestHandler):
def do_GET(self):
self._proxy()
def do_POST(self):
self._proxy()
def do_PATCH(self):
self._proxy()
def _proxy(self):
length = int(self.headers.get("content-length", "0") or "0")
body = self.rfile.read(length) if length else None
headers = {
key: value
for key, value in self.headers.items()
if key.lower() not in HOP_HEADERS
}
request = Request(
TARGET + self.path,
data=body,
headers=headers,
method=self.command,
)
try:
timeout = 360 if self.command == "POST" else 30
with urlopen(request, timeout=timeout) as response:
payload = response.read()
self.send_response(response.status)
for key, value in response.headers.items():
if key.lower() not in HOP_HEADERS:
self.send_header(key, value)
self.end_headers()
self.wfile.write(payload)
except HTTPError as exc:
payload = exc.read()
self.send_response(exc.code)
self.end_headers()
self.wfile.write(payload)
except URLError as exc:
self.send_response(502)
self.end_headers()
self.wfile.write(str(exc).encode())
ThreadingHTTPServer(("0.0.0.0", 18081), Proxy).serve_forever()
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
---
---
apiVersion: batch/v1
kind: Job

View file

@ -513,11 +513,19 @@ def _daily_triage_digest(params: dict[str, Any]) -> str:
max_workstreams = int(params.get("max_workstreams", 12))
max_next_steps = int(params.get("max_next_steps", 8))
open_workstreams = _open_workstream_digest(summary, workplan_index, max_workstreams)
ranked_suggestions = summary.get("ranked_suggestions") or []
if not isinstance(ranked_suggestions, list):
ranked_suggestions = []
digest = {
"generated_at": summary.get("generated_at"),
"totals": summary.get("totals", {}),
"open_workstreams": open_workstreams,
"next_steps": [_safe_next_step(item) for item in next_steps[:max_next_steps]],
"ranked_suggestions": [
_safe_ranked_suggestion(item)
for item in ranked_suggestions[: int(params.get("max_suggestions", 10))]
],
"inbox": {
"unread_count": len(inbox),
"samples": [_safe_inbox_item(item) for item in inbox[:3]],
@ -619,6 +627,19 @@ def _safe_next_step(item: dict[str, Any]) -> dict[str, Any]:
}
def _safe_ranked_suggestion(item: dict[str, Any]) -> dict[str, Any]:
return {
"id": item.get("id"),
"title": _short_text(item.get("title", ""), 120),
"stage": item.get("stage"),
"domain_slug": item.get("domain_slug"),
"origin_ref": item.get("origin_ref"),
"relevance": item.get("relevance"),
"wsjf": item.get("wsjf"),
"last_requested_at": item.get("last_requested_at"),
}
def _safe_inbox_item(item: dict[str, Any]) -> dict[str, Any]:
return {
"id": item.get("id"),

View file

@ -486,6 +486,18 @@ def test_daily_triage_digest_is_curated_scalar_json(monkeypatch) -> None:
"/state/summary": {
"generated_at": "2026-05-19T05:20:00Z",
"totals": {"tasks": {"todo": 4, "wait": 1}},
"ranked_suggestions": [
{
"id": "sug-1",
"title": "Issue-core ingestion API key path",
"stage": "suggestion",
"domain_slug": "custodian",
"origin_ref": "issue-core-ingestion-api-key",
"relevance": 2,
"wsjf": 4.7,
"last_requested_at": "2026-05-19T04:00:00Z",
}
],
"topics": [
{
"slug": "custodian",
@ -594,3 +606,4 @@ def test_daily_triage_digest_is_curated_scalar_json(monkeypatch) -> None:
assert digest["deterministic_scoring"]["future_mode"] == (
"code_score_high_gain_high_effort_candidates"
)
assert digest["ranked_suggestions"][0]["origin_ref"] == "issue-core-ingestion-api-key"

View file

@ -4,11 +4,11 @@ type: workplan
title: "Weekly Coding Retrospection schedule (Saturday evenings)"
domain: custodian
repo: activity-core
status: blocked
status: active
owner: codex
topic_slug: custodian
created: "2026-06-07"
updated: "2026-06-17"
updated: "2026-07-03"
state_hub_workstream_id: "7387fc50-1f2c-471a-9d85-bb085cbd0b63"
---
@ -107,3 +107,11 @@ specs because that weekly read model has zero suggestions. The schedule remains
disabled until a non-empty weekly read model, or an explicit operator decision
that a zero-suggestion dry-run is an acceptable enablement proof, confirms
correct routing and no duplicate target tasks on re-run.
2026-07-03 reevaluation: `AGENTIC-WP-0010` remains finished and the resolver
smoke still works, but State Hub still has only the 2026-06-07 weekly
`coding_retro` read model (`ec20ac1c`, `window.days=7`) with zero suggestions.
No newer weekly publish exists yet. This is a **time-controlled wait** on the
next Saturday 19:00 Europe/Berlin publish (or an operator decision to enable on
the zero-suggestion proof), not a hard blocker. Workplan status returns to
`active`; T03 stays `wait`.

View file

@ -4,11 +4,11 @@ type: workplan
title: "Intent gap closure"
domain: custodian
repo: activity-core
status: blocked
status: active
owner: codex
topic_slug: custodian
created: "2026-06-16"
updated: "2026-06-18"
updated: "2026-07-03"
state_hub_workstream_id: "d64cfbba-6da7-4737-afb9-866afa0e9cda"
---
@ -38,7 +38,7 @@ The preserved analysis lives in:
```task
id: ACTIVITY-WP-0009-T01
status: wait
status: done
priority: high
state_hub_task_id: "7012e4fd-2530-49b7-9c2f-1d949809a144"
```
@ -73,6 +73,12 @@ fixture smoke passed. The remaining work is the activity-core / Railiance
runtime reconciliation and daily-triage evidence collection path captured in
`ACTIVITY-WP-0010`.
2026-07-03 closeout: `ACTIVITY-WP-0010` and `ACTIVITY-WP-0006-T03` now record
three consecutive clean scheduled daily triage runs (2026-06-28 through
2026-06-30, streak continuing through 2026-07-03) with matching State Hub
progress, working-memory notes, and calibration feedback. The scheduled-run trust
gap is closed. T01 is done.
## Promote Issue-Core Task Emission Safely
```task
@ -100,6 +106,10 @@ Current wait reason: production Railiance currently uses null-sink audit mode;
live issue-core credentials/access and duplicate-handling are not yet verified
for this repo.
2026-07-03 reevaluation: this is an external-credential gate, not a workplan
blocker. Keep T02 at `wait` with `blocking_reason` describing the issue-core
approval path; the workplan returns to `active`.
## Resolve Review-Required Contract Drift
```task
@ -231,7 +241,6 @@ Agent-actionable closure is complete for T03, T04, T05, and T06.
Remaining waits:
- T01 waits on real scheduled daily triage run evidence.
- T02 waits on issue-core production endpoint/credentials and duplicate-handling
approval.

View file

@ -4,11 +4,11 @@ type: workplan
title: "Daily Triage LLM Reconciliation And Evidence"
domain: custodian
repo: activity-core
status: blocked
status: finished
owner: codex
topic_slug: custodian
created: "2026-06-18"
updated: "2026-06-27"
updated: "2026-07-03"
state_hub_workstream_id: "f2c73ac6-13f0-4005-82cc-76c7c9f9c8b9"
---
@ -135,7 +135,7 @@ Hub handoff message `9a074b7c-4b87-4e3c-a6bf-e1fe5580daa8` asks
```task
id: ACTIVITY-WP-0010-T03
status: wait
status: done
priority: high
state_hub_task_id: "10e0df77-c230-4a82-b720-23c66bd17c0a"
```
@ -173,11 +173,17 @@ Done when:
after the WP-0016 code/schema/runtime-prompt deployment due the 2026-06-26 and
2026-06-27 malformed-output failures.
2026-07-03 closeout: `ACTIVITY-WP-0016` is finished and scheduled
`daily_triage` progress from **2026-06-28 through 2026-07-03** all show
`output_validated=true` with working-memory notes. The `railiance-cluster`
inbox reply (`e360e38f`, 2026-07-01) confirms the live runtime, provider Secret
presence, and in-namespace fixture smoke. T03 is done.
## Collect Three Clean Scheduled Runs
```task
id: ACTIVITY-WP-0010-T04
status: wait
status: done
priority: high
state_hub_task_id: "dc6b9482-cf43-4fc5-994b-dcd7dea47db7"
```
@ -204,11 +210,17 @@ Done when:
Railiance runtime prompt and max_tokens changes, run a live smoke, then restart
the three-consecutive-scheduled-run gate from zero.
2026-07-03 closeout: post-`ACTIVITY-WP-0016` scheduled runs on **2026-06-28,
2026-06-29, and 2026-06-30** (`6a44d6dd`, `1dfb47c9`, `ac3d71a0`) are three
consecutive clean scheduled successes with matching State Hub progress and
working-memory notes. The streak continued through 2026-07-03. Calibration
feedback was already recorded when `ACTIVITY-WP-0006-T03` closed. T04 is done.
## Close Handoff State
```task
id: ACTIVITY-WP-0010-T05
status: wait
status: done
priority: medium
state_hub_task_id: "ecc57e21-1716-4daa-aba6-d8a6d824e4ed"
```
@ -223,3 +235,8 @@ Done when:
- any temporary `needs_human` flags created for the llm-connect provider/config
handoff are cleared or replaced by a narrower follow-up;
- this workplan is marked `finished`.
2026-07-03 closeout: `ACTIVITY-WP-0006-T03` already records the three-run
calibration evidence. `ACTIVITY-WP-0009-T01` is updated in the same pass.
No temporary `needs_human` flags remain for the llm-connect provider/config
handoff. T05 is done; this workplan is `finished`.

View file

@ -4,11 +4,11 @@ type: workplan
title: "Adopt State Hub Beachhead Endpoint"
domain: infotech
repo: activity-core
status: blocked
status: active
owner: claude
topic_slug: activity-core
created: "2026-06-24"
updated: "2026-06-24"
updated: "2026-07-03"
state_hub_workstream_id: "bbc07f9e-9323-4b2b-b556-c33b37d0b228"
---
@ -19,10 +19,15 @@ Carries the **blocked remainder** of [[ACTIVITY-WP-0014]] T05. The in-repo half
client-side adoption that depends on the state-hub-owned **beachhead** capability
(per-machine read cache + write outbox) existing first.
**Blocked on:** the state-hub beachhead (proposal sent to the `state-hub` agent,
**Waiting on:** the state-hub beachhead (proposal sent to the `state-hub` agent,
2026-06-23). Do not build queue/cache logic in activity-core — see
[[statehub-beachhead-principle]].
2026-07-03 reevaluation: no state-hub-owned beachhead endpoint is available yet.
`CUST-WP-0054` now tracks a files-first dev beachhead, but activity-core client
adoption still depends on the state-hub capability shipping first. Both tasks
remain `wait` on external delivery; the workplan is `active`, not `blocked`.
## Point STATE_HUB_URL at the beachhead
```task

View file

@ -4,7 +4,7 @@ type: workplan
title: "LLM Output Robustness & The Producer Trust Boundary"
domain: custodian
repo: activity-core
status: active
status: finished
owner: codex
topic_slug: custodian
created: "2026-06-26"
@ -90,7 +90,7 @@ there are two sensible strategies — and they compose:
```task
id: ACTIVITY-WP-0016-T01
status: wait
status: cancel
priority: high
state_hub_task_id: "74fd16a5-4ea5-4dfe-8526-dfa27cf76138"
```
@ -353,7 +353,7 @@ Done when:
```task
id: ACTIVITY-WP-0016-T05
status: progress
status: done
priority: high
state_hub_task_id: "c881500b-5459-4620-81c0-b176971e989f"
```
@ -415,3 +415,20 @@ for the next 07:20 Berlin fire, then confirm State Hub `daily_triage` evidence i
- **Boundary discipline:** keeps activity-core inside its SCOPE — this hardens
the instruction-executor output contract; it does not move provider
credentials, cluster reconciliation, or task lifecycle into this repo.
## Closure 2026-07-02 (RAIL-BS-WP-0008 live deploy)
- T05 done: the robustness bundle (strict per-item schema + T03 quarantine
parser + bounded top-7/NDJSON runtime prompt, activity-core `7612112`) was
deployed to railiance01 and live-proven. A manually triggered daily-triage
run produced a clean schema-valid report with exactly 7 ranked
recommendations: State Hub event `24d2d321-c761-47f7-bf9e-7950a6253c21`,
`output_validated=true`, working memory written. Calibration re-entry: the
three-clean-run streak (WP-0006-T03 / WP-0010-T04) restarts from this run.
- T01 cancelled: the raw 2026-06-26 llm-connect response is unrecoverable
(stateless pod, no response store, log stream holds only 2 startup lines
since 2026-06-19). Root cause stands on the retained 4000-char preview and
break-at-char-5268 evidence: output exceeded the old ~1200-token budget and
truncated mid-JSON. The deployed mitigation (1800-token headroom, bounded
top-7, per-item recovery) addresses exactly that failure mode.