From 86bb550c7a0830b27558a569d65807cfcb14a209 Mon Sep 17 00:00:00 2001 From: tegwick Date: Tue, 21 Jul 2026 23:42:15 +0200 Subject: [PATCH] Add ACTIVITY-WP-0024 operator automation console workplan Propose API-first ops console: status/inventory/runs REST, fail-closed operator token, Run now + pause controls, then thin UI. No cron edit or public Ingress in MVP. --- ...ITY-WP-0024-operator-automation-console.md | 278 ++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 workplans/ACTIVITY-WP-0024-operator-automation-console.md diff --git a/workplans/ACTIVITY-WP-0024-operator-automation-console.md b/workplans/ACTIVITY-WP-0024-operator-automation-console.md new file mode 100644 index 0000000..bb20e4f --- /dev/null +++ b/workplans/ACTIVITY-WP-0024-operator-automation-console.md @@ -0,0 +1,278 @@ +--- +id: ACTIVITY-WP-0024 +type: workplan +title: "Operator automation console (status API + control plane + thin UI)" +domain: infotech +repo: activity-core +status: proposed +owner: codex +topic_slug: activity-core +created: "2026-07-21" +updated: "2026-07-21" +--- + +# Operator automation console (status API + control plane + thin UI) + +## Origin + +2026-07-21 operator discussion after ACTIVITY-WP-0023 closeout. Operators need a +first-class surface for scheduled automations without SSH + SQL + Temporal UI +as the only path. + +Builds on: + +- **ACTIVITY-WP-0018** — own-infra automation status contract + CLI +- **ACTIVITY-WP-0019** — automation inventory Make targets +- **ACTIVITY-WP-0021** — prod automation status path (SSH helper) + +Locked product decisions (founder): + +| Fork | Choice | +| --- | --- | +| Surface | API-first, then thin UI **in activity-core** | +| Auth / exposure | Port-forward + operator token; mutations **fail-closed** | +| Mutations in MVP | **Run now + enable/disable/pause only** (no cron patch) | + +## Goal + +Ship an **operator automation console**: HTTP APIs (and a thin UI) so an +operator can: + +1. See whether regular scheduled jobs ran properly in a time window +2. Review results (runs → evidence: tasks spawned, progress refs, report paths) +3. Run a defined activity instantly +4. Enable / disable / pause schedules without SSH + SQL + +This is **not** an end-user task tracker and **not** a second scheduler. Durable +scheduling remains Temporal + ActivityDefinitions; the console is a consumer and +control plane over that truth. + +## Out of scope + +- Cron / timezone patching in the UI (schedules stay git-owned; edit files + sync) +- Authoring or editing rules / instructions / templates in the UI +- Public Ingress or full OIDC/key-cape (follow-up after MVP) +- Hosting the console in the state-hub dashboard +- Task lifecycle UI (create/assign/close tasks) +- Replacing Temporal UI for workflow debugging (deep-link only) + +## Architecture sketch + +``` +Operator (browser / curl) + │ port-forward svc/actcore-api + │ header: X-Operator-Token (or agreed scheme) + ▼ +actcore-api + GET /ops/automations + GET /ops/automations/status?since=&until= + GET /ops/automations/{id} + GET /ops/automations/{id}/runs + POST /ops/automations/{id}/trigger + POST /ops/automations/{id}/enable|disable|pause|unpause + GET /ops/ui/… (static/HTMX after API stable) + │ + ├─ activity_core.automation_status + inventory + ├─ activity_runs + activity_definitions + ├─ Temporal schedule describe / pause + └─ audit (progress event or ops_audit; no secrets) +``` + +Deep-links into State Hub / edge when evidence lives there (G9-aware). + +## Auth policy (MVP) + +- Mutations require an operator token when + `ACTIVITY_CORE_OPERATOR_TOKEN` (or ESO-backed secret) is configured. +- If the token is **unset** under production posture, **refuse mutations** + (fail-closed). Do not leave unauthenticated Run now on a reachable API. +- Token never logged or returned by API. +- Access path: `kubectl -n activity-core port-forward` to the API Service. +- Ingress + OIDC is an explicit follow-up, not an MVP gate. +- Credential custody via `warden route` / OpenBao — never git, chat, or workplan. + +## Mutation policy (MVP) + +| Action | Behavior | +| --- | --- | +| Run now | Wrap existing trigger; return `workflow_id`; UI confirms for side-effect defs | +| Disable / pause | Coherent model: definition enabled flag and/or Temporal schedule paused | +| Enable / unpause | Inverse | +| Change cron / timezone | **Out of MVP** — definition files + sync; UI shows schedule read-only | + +## Tasks + +## Task: Product brief and SCOPE clarification + +```task +id: ACTIVITY-WP-0024-T01 +status: todo +priority: high +``` + +1. Write a short product brief (personas, jobs-to-be-done, non-goals) in this + workplan or `docs/` if it outgrows the file. +2. Update `SCOPE.md`: **operator automation console is in scope**; end-user + task management remains out of scope. Clarify G10 (auth MVP vs public access). +3. Cross-link WP-0018/0019 as the evidence/inventory contracts this console wraps. + +**Done when:** SCOPE and this workplan tell one story; non-goals are explicit. + +## Task: Operator token auth and fail-closed mutations + +```task +id: ACTIVITY-WP-0024-T02 +status: todo +priority: high +``` + +1. Design operator token check (e.g. `X-Operator-Token` header compared to + env/secret) for all `/ops` **mutations**. +2. Fail-closed: when production requires auth and token is missing/misconfigured, + mutations return 401/403 (not silent open). +3. Document env name, ESO/bootstrap option, and port-forward access in runbook. +4. Never put the token value in git, logs, or State Hub detail. + +**Done when:** unauthenticated mutation is rejected under the configured posture; +runbook describes custody without leaking secrets. + +## Task: REST inventory and status window + +```task +id: ACTIVITY-WP-0024-T03 +status: todo +priority: high +``` + +1. `GET /ops/automations` — inventory equivalent to WP-0019 (cron/scheduled defs, + enabled, schedule expression, Temporal schedule id / paused hints). +2. `GET /ops/automations/status?since=&until=` — wraps WP-0018 automation-status + semantics (JSON). +3. `GET /ops/automations/{id}` — single definition + schedule visibility. +4. Prefer reusing `activity_core.automation_status` / inventory modules; do not + fork a second evidence contract. + +**Done when:** curl against the API matches CLI status/inventory for the same +window within documented field mapping. + +## Task: REST run history and evidence summary + +```task +id: ACTIVITY-WP-0024-T04 +status: todo +priority: high +``` + +1. `GET /ops/automations/{id}/runs?since=` (and optional global runs list). +2. Each run: `run_id`, `scheduled_for`, `fired_at`, `tasks_spawned`, version, + and evidence pointers when known (progress event types/ids, report paths). +3. No secrets, raw LLM output, or full prompts in responses. + +**Done when:** operator can list recent runs for a definition without SSH/SQL. + +## Task: REST Run now and enable/disable/pause with audit + +```task +id: ACTIVITY-WP-0024-T05 +status: todo +priority: high +``` + +1. `POST /ops/automations/{id}/trigger` — wrap existing trigger path; require + operator token. +2. `POST .../enable|disable|pause|unpause` — one coherent model documented in + the PR (definition flag vs Temporal pause; prefer both consistent). +3. Audit trail: who/when/what (operator label optional; never store token). Prefer + State Hub progress `event_type` or a small `ops_audit` table. +4. Side-effect definitions (e.g. forgejo prune apply): document confirmation + expectation for UI; API may accept an explicit `confirm_side_effect=true`. + +**Done when:** authenticated Run now returns `workflow_id` and produces run +evidence; pause/disable visible in inventory/status; unauthenticated mutate fails. + +## Task: Contract and security tests + +```task +id: ACTIVITY-WP-0024-T06 +status: todo +priority: high +``` + +1. Contract tests for inventory/status/runs JSON shapes. +2. Auth tests: missing token → reject mutations; valid token → allow. +3. Response fixtures scanned so secrets/token values never appear. + +**Done when:** CI/unit tests cover the above without a live cluster. + +## Task: Thin operator UI on actcore-api + +```task +id: ACTIVITY-WP-0024-T07 +status: todo +priority: medium +``` + +1. Static/HTMX (or minimal SPA) served from actcore-api under `/ops/ui/`. +2. Screens: automation list, status window, run history, Run now + enable/pause + actions (token supplied via header or session form — no token in URLs). +3. Schedule fields **read-only** in MVP. +4. Confirm dialog for side-effect activities. + +**Done when:** usable via port-forward for the MVP jobs-to-be-done. + +## Task: Prod access path (no public Ingress) + +```task +id: ACTIVITY-WP-0024-T08 +status: todo +priority: medium +``` + +1. Document port-forward (or equivalent) for railiance01. +2. Wire operator token into runtime secret path (bootstrap or ESO) without + committing values. +3. Explicitly **do not** add public Ingress in this workplan. +4. Optional: NetworkPolicy note that API remains ClusterIP. + +**Done when:** runbook has a copy-paste operator access path; G10 public access +still deferred with a clear follow-up note. + +## Task: Runbook daily checklist mapping + +```task +id: ACTIVITY-WP-0024-T09 +status: todo +priority: low +``` + +1. Map “How did automations go since Sunday?” to `/ops/automations/status` and UI. +2. Map “Run X now” and “pause X” to mutation endpoints. +3. Keep CLI (`make automation-status`) as valid offline/alternate path. + +**Done when:** runbook section points operators at console first, CLI second. + +## Success criteria + +- [ ] `GET /ops/automations/status?since=…` matches CLI automation-status semantics +- [ ] Operator can list last N runs for a definition without SSH/SQL +- [ ] Authenticated Run now returns workflow_id and produces `activity_runs` evidence +- [ ] Pause/disable visible in inventory/status and Temporal schedule state +- [ ] Unauthenticated mutation returns 401/403 when token is configured +- [ ] Thin UI usable via port-forward for the above flows +- [ ] Runbook documents token custody without secrets in git + +## Implementation order + +1. T01 SCOPE/brief +2. T02 auth + T03/T04/T05 API (before UI) +3. T06 tests green +4. T07 thin UI +5. T08/T09 docs + prod token wiring +6. Deploy railiance01 image; no Ingress + +## References + +- Plan: session plan “Operator dashboard for activity-core scheduled automations” +- `src/activity_core/automation_status.py`, `src/activity_core/api.py` +- `docs/runbook.md`, `SCOPE.md` G10 +- ACTIVITY-WP-0018, ACTIVITY-WP-0019, ACTIVITY-WP-0021