2026-08-20 11:20:23 +02:00
|
|
|
---
|
|
|
|
|
id: ACTIVITY-WP-0031
|
|
|
|
|
type: workplan
|
|
|
|
|
title: "Production automation execution reliability cleanup"
|
|
|
|
|
domain: infotech
|
|
|
|
|
repo: activity-core
|
|
|
|
|
status: active
|
|
|
|
|
owner: codex
|
|
|
|
|
topic_slug: activity-core
|
|
|
|
|
created: "2026-08-20"
|
2026-09-04 17:47:42 +02:00
|
|
|
updated: "2026-09-04"
|
2026-08-20 11:20:23 +02:00
|
|
|
related:
|
|
|
|
|
- ACTIVITY-WP-0021
|
|
|
|
|
- ACTIVITY-WP-0022
|
|
|
|
|
- ACTIVITY-WP-0026
|
|
|
|
|
- ACTIVITY-WP-0030
|
2026-08-22 22:52:34 +02:00
|
|
|
state_hub_workstream_id: "93b37937-a29b-505e-adc2-390980cd8ceb"
|
2026-08-20 11:20:23 +02:00
|
|
|
---
|
|
|
|
|
|
|
|
|
|
# Production automation execution reliability cleanup
|
|
|
|
|
|
|
|
|
|
## Goal
|
|
|
|
|
|
|
|
|
|
Make production automation health reflect completed execution rather than only
|
|
|
|
|
successful schedule fires, stop known task floods, and repair the repository
|
|
|
|
|
contracts found during the 2026-08-20 activity-core review.
|
|
|
|
|
|
|
|
|
|
## Restore provider-backed execution
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: ACTIVITY-WP-0031-T01
|
|
|
|
|
status: wait
|
|
|
|
|
priority: high
|
2026-08-22 22:52:34 +02:00
|
|
|
state_hub_task_id: "d84116ae-8219-569a-8d7b-e4eb83c192c3"
|
2026-08-20 11:20:23 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Production FI, Binky, and daily-triage runs reach `llm-connect` but fail after
|
|
|
|
|
three attempts. An in-cluster fixture returned a sanitized upstream OpenRouter
|
|
|
|
|
HTTP 401. Credential ownership is the `railiance-platform` OpenBao lane
|
|
|
|
|
(`openrouter-llm-connect`); activity-core must not bypass that custody boundary.
|
|
|
|
|
Track rotation/reconciliation, restart, and a successful fixture smoke as the
|
|
|
|
|
exit evidence.
|
|
|
|
|
|
2026-08-20 22:47:18 +02:00
|
|
|
Progress 2026-08-20: railiance-platform repaired the delivery half. The
|
|
|
|
|
activity-core ESO bootstrap default now includes the approved exact-path
|
|
|
|
|
llm-connect policy, its replacement token reports read capability, and the
|
|
|
|
|
reviewed `ExternalSecret` is `Ready=True` / `SecretSynced` on railiance01. It
|
|
|
|
|
took ownership of the one-key Secret, llm-connect rolled out, and the real
|
|
|
|
|
actcore-worker reaches `/health` through the Service. The post-restart fixture
|
|
|
|
|
still returns sanitized OpenRouter HTTP 401, proving the canonical key itself
|
|
|
|
|
is rejected. T01 remains `wait` on an attended OpenRouter account owner to mint
|
|
|
|
|
and safely provision a replacement key; no key value was read or printed.
|
|
|
|
|
|
fix(llm): surface llm-connect's error body instead of a bare 502
llm-connect maps every provider API error onto HTTP 502 and puts the real
cause in the body (llm_connect/server.py::_error_response: error,
provider_status). LLMConnectClient.complete called raise_for_status() and threw
that body away, so a revoked OpenRouter key was indistinguishable from a downed
gateway — four days of production evidence read as "llm-connect is down".
Live check confirms one fault, not two: the llm-connect pod is Running 1/1 with
healthy endpoints, and today's FI/Binky/triage runs still 502 after yesterday's
rollout, matching the sanitized upstream 401 railiance-platform reported.
The client now raises with error, provider_status, provider, model and a
bounded copy of llm-connect's already-sanitized message, under a field
allowlist so no provider blob or key material reaches the run artefact.
Refs ACTIVITY-WP-0031-T01, T03.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 08:53:30 +02:00
|
|
|
Progress 2026-08-21 (activity-core half, no custody boundary crossed): live
|
|
|
|
|
evidence confirms a single fault, not two. FI, Binky, and daily triage still
|
|
|
|
|
fail today (`05:20` / `05:30` / `06:23` UTC) with `502 Bad Gateway` from
|
|
|
|
|
llm-connect — **after** yesterday's rollout (`llm-connect` pod is `Running`
|
|
|
|
|
1/1, endpoints healthy). That 502 is not a dead gateway:
|
|
|
|
|
`llm_connect/server.py::_error_response` maps **every** `LLMAPIError` onto 502
|
|
|
|
|
and carries the real cause in the body (`error`, `provider_status`). So the
|
|
|
|
|
502s and the reported upstream 401 are the same rejected key.
|
|
|
|
|
|
|
|
|
|
`LLMConnectClient.complete` called `raise_for_status()` and discarded that
|
|
|
|
|
body, so four days of production evidence read as "llm-connect is down" when it
|
|
|
|
|
meant "the provider rejected the key". Fixed: the client now raises with
|
|
|
|
|
`error`, `provider_status`, `provider`, `model`, and a bounded copy of
|
|
|
|
|
llm-connect's already-sanitized `message`, under a field allowlist so no
|
|
|
|
|
provider blob or key material can reach the run artefact. Five tests cover the
|
|
|
|
|
401-behind-502 case, the allowlist, bounding, and unusable bodies.
|
|
|
|
|
|
|
|
|
|
The identical body-discarding call exists in
|
|
|
|
|
`rein-aharness/rein_aharness/llm_connect_client.py:65`, which is what produces
|
|
|
|
|
the opaque ops_run failure text in the status table. Not ours to edit —
|
|
|
|
|
handed to rein-aharness.
|
|
|
|
|
|
|
|
|
|
T01 still `wait`: the key rotation itself remains attended and
|
|
|
|
|
railiance-platform-owned. What changed is that the next failure will name its
|
|
|
|
|
own cause.
|
|
|
|
|
|
2026-08-21 09:06:36 +02:00
|
|
|
Diagnosis verified 2026-08-21 (previously relayed, now tested). Direct probe
|
|
|
|
|
from the llm-connect pod, no secret read or printed:
|
|
|
|
|
|
|
|
|
|
- `POST /execute` → `502 {"error":"provider_api_error","provider_status":401,
|
|
|
|
|
"message":"HTTP 401 from https://openrouter.ai/api/v1/chat/completions"}`
|
|
|
|
|
- `GET https://openrouter.ai/api/v1/key` with the delivered key →
|
|
|
|
|
**`401 {"error":{"message":"User not found.","code":401}}`**
|
|
|
|
|
|
|
|
|
|
"User not found" is OpenRouter's wording for a key that resolves to **no
|
|
|
|
|
account**. It is not insufficient credits (402) and not a model-permission
|
|
|
|
|
problem (403), so **no new OpenRouter account is required** — the existing
|
|
|
|
|
account needs a new key issued, because this key value is dead.
|
|
|
|
|
Key fingerprint for identification: `sha256[:12] = ab938241a2ec`, length 73
|
|
|
|
|
(+1, see below), prefix `sk-or-v1-`.
|
|
|
|
|
|
|
|
|
|
Ruled out along the way: provider/model config is correct
|
|
|
|
|
(`LLM_CONNECT_PROVIDER=openrouter`, `google/gemini-2.5-flash`); the Service and
|
|
|
|
|
pod are healthy; the ExternalSecret delivers exactly one key under the expected
|
|
|
|
|
name.
|
|
|
|
|
|
|
|
|
|
**Separate latent defect, railiance-platform lane:** the delivered secret has a
|
|
|
|
|
trailing newline (74 bytes for a 73-char key; `urllib` refuses it as a header
|
|
|
|
|
value outright). It is currently harmless only because
|
|
|
|
|
`llm_connect/config.py:53` calls `.strip()` on the env value. Any consumer that
|
|
|
|
|
does not strip would fail on a perfectly valid key. Worth fixing in the
|
|
|
|
|
OpenBao→ESO lane while the key is being replaced.
|
|
|
|
|
|
2026-09-04 17:49:08 +02:00
|
|
|
Rechecked 2026-09-04 without reading or printing the value. The canonical
|
|
|
|
|
OpenBao record is still KV version 1 created 2026-07-02. Its ESO-managed
|
|
|
|
|
Kubernetes Secret and the running `llm-connect` process have the same 74-byte
|
|
|
|
|
fingerprint `ab938241a2ec`; production continues to return sanitized upstream
|
|
|
|
|
401. Thus no replacement is waiting for a pod restart. The only other cataloged
|
|
|
|
|
OpenRouter lane is scoped to `rein-openweights` and is not transferable without
|
|
|
|
|
an ownership decision. Reconciliation request
|
|
|
|
|
`c32901ff-2072-4b93-81cd-db93dddfa5f3` asks railiance-platform to install a
|
|
|
|
|
newly issued, newline-free key at the canonical path, allow ESO to sync,
|
|
|
|
|
restart `llm-connect`, and return value-free fixture evidence.
|
|
|
|
|
|
2026-08-20 11:20:23 +02:00
|
|
|
## Emergency-pause weekly SBOM fan-out
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: ACTIVITY-WP-0031-T02
|
|
|
|
|
status: done
|
|
|
|
|
priority: high
|
2026-08-22 22:52:34 +02:00
|
|
|
state_hub_task_id: "53c16356-b80d-50f7-a4a1-b70b67eb0178"
|
2026-08-20 11:20:23 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Disable `weekly-sbom-staleness` in source and on railiance01 before the next
|
|
|
|
|
Monday window. The bounded daily replacement remains owned by ACTIVITY-WP-0030;
|
|
|
|
|
this task is the immediate containment measure for the observed 75-task fire.
|
|
|
|
|
|
|
|
|
|
Completed 2026-08-20: source, live DB, and Temporal schedule are disabled. The
|
|
|
|
|
new image and ConfigMap projection were deployed; schedule reconciliation
|
|
|
|
|
reports the definition as paused.
|
|
|
|
|
|
|
|
|
|
## Report execution outcomes in production status
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: ACTIVITY-WP-0031-T03
|
|
|
|
|
status: done
|
|
|
|
|
priority: high
|
2026-08-22 22:52:34 +02:00
|
|
|
state_hub_task_id: "d70cfca0-3c3b-5bfd-abb9-3f07b52b2c9b"
|
2026-08-20 11:20:23 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Extend `scripts/prod_automation_status.sh` with ops-run outcome counts, bounded
|
|
|
|
|
failed/open detail, and daily-triage progress validation evidence. Preserve
|
|
|
|
|
sanitized error output and keep the command deterministic and read-only.
|
|
|
|
|
|
|
|
|
|
Completed 2026-08-20. The live report now shows ops-run state counts, bounded
|
|
|
|
|
failure/open detail, and bounded State Hub `daily_triage` validation evidence.
|
|
|
|
|
It exposed today's FI/Binky 502 failures and triage `output_validated=false`
|
|
|
|
|
beside otherwise healthy schedule-fire counts.
|
|
|
|
|
|
|
|
|
|
## Reconcile implementation and test contracts
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: ACTIVITY-WP-0031-T04
|
|
|
|
|
status: done
|
|
|
|
|
priority: medium
|
2026-08-22 22:52:34 +02:00
|
|
|
state_hub_task_id: "4f44ec1b-65fb-56bb-9fdf-a7705434e09b"
|
2026-08-20 11:20:23 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Repair the four reproducible suite failures, keep runtime-path resolution out of
|
|
|
|
|
the rules package boundary, and document that `dedupe_key_strategy` is retained
|
|
|
|
|
metadata rather than repeated-content suppression.
|
|
|
|
|
|
|
|
|
|
Completed 2026-08-20. Runtime URI resolution now happens before the pure rules
|
|
|
|
|
boundary; stale assertions/test doubles are reconciled; disabled one-shots are
|
|
|
|
|
deleted idempotently during schedule sync; and the dedupe contract is truthful.
|
|
|
|
|
Verification: `347 passed, 1 skipped`; a subsequent focused warning regression
|
|
|
|
|
passed `10 passed` without warnings.
|
|
|
|
|
|
|
|
|
|
## Repair consumer routing and State Hub metadata
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: ACTIVITY-WP-0031-T05
|
|
|
|
|
status: wait
|
|
|
|
|
priority: medium
|
2026-08-22 22:52:34 +02:00
|
|
|
state_hub_task_id: "a7eb3615-dd11-54c9-80ec-a147d100f8b7"
|
2026-08-20 11:20:23 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Make the OpenBao retention reactivation task explicitly claimable without
|
|
|
|
|
authorizing destructive cleanup. Route Binky's missing workload credential
|
|
|
|
|
front door and the duplicate legacy workstream identifiers to their canonical
|
|
|
|
|
owners. Clear stale human-needed flags only for already-terminal activity-core
|
|
|
|
|
tasks.
|
|
|
|
|
|
|
|
|
|
Activity-core cleanup is complete: three terminal tasks no longer retain stale
|
|
|
|
|
`needs_human` flags. External handoffs were sent to binky-control and
|
|
|
|
|
railiance-platform for mail credential materialization, repo-manager for the
|
|
|
|
|
duplicate registrar IDs, and railiance-master for the unclaimed retention
|
|
|
|
|
closeout. The expired retention one-shot is disabled; its existing open ops run
|
|
|
|
|
remains operator-visible and cannot authorize destructive cleanup.
|
|
|
|
|
|
2026-09-04 17:47:42 +02:00
|
|
|
Progress 2026-09-04: the Binky mail lane was already provisioned; its runtime
|
|
|
|
|
discovery was broken. OpenBao was healthy, OpenBao v2.5.4 existed at
|
|
|
|
|
`/home/tegwick/.local/bin/bao`, and the mode-0600 AppRole files existed under
|
|
|
|
|
`~/.local/rein-aharness/approle-binky-mail`, but the rein claim-loop omitted
|
|
|
|
|
both locations. `rein-aharness` commit `aedfadd` now supplies the non-secret
|
|
|
|
|
OpenBao/AppRole defaults and includes `~/.local/bin` in `PATH`. The corrected
|
|
|
|
|
unit is live and healthy. A value-free smoke proved `read` on the exact Binky
|
|
|
|
|
IMAP path, `deny` on a sibling path, and presence of both required IMAP fields;
|
|
|
|
|
the rein suite passed 224 tests with one skip. T05 remains `wait` only for its
|
|
|
|
|
other named external metadata/retention handoffs.
|
|
|
|
|
|
2026-08-20 11:20:23 +02:00
|
|
|
## Acceptance
|
|
|
|
|
|
|
|
|
|
- [x] Weekly SBOM fan-out is disabled in source and production
|
|
|
|
|
- [x] Production status distinguishes schedule fires from execution failures
|
|
|
|
|
- [x] Full test suite is green
|
|
|
|
|
- [ ] Provider and consumer prerequisites have named owners and evidence
|
|
|
|
|
- [x] Workplan and State Hub task state are consistent
|