activity-core/workplans/ACTIVITY-WP-0026-ops-run-claim-queue.md
tegwick 6ce77a72bb
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Document ACTIVITY-WP-0026-T07 railiance deploy checklist.
Add deploy-ops-run-queue-railiance.md (image, migrate 0007, smoke, dual-path
residual), wire OPS_RUN_* into runtime ConfigMap, and cross-link runbook/README.
T07 stays open until prod smoke is executed.
2026-08-03 19:30:00 +02:00

6.6 KiB

id type title domain repo status owner topic_slug priority created updated depends_on related state_hub_workstream_id
ACTIVITY-WP-0026 workplan Ops run claim queue — durable claimable work for scheduled automation infotech activity-core in_progress grok activity-core high 2026-08-03 2026-08-03
ACT-ADR-005
ACTIVITY-WP-0022
ACTIVITY-WP-0023
REIN-A-0002
ISSUE-WP-0006
STATE-WP-0078
c8f1eaa3-6d1a-4002-bb1f-fc250ed353fe

ACTIVITY-WP-0026 — Ops run claim queue

Origin

ACT-ADR-005 (ops runs vs development work records). Closes G2 executor gap without reopening default Forgejo issue spam (ACTIVITY-WP-0022).

Goal

Make internal scheduled automation emit a claimable ops_run in activity-core so rein-aharness (and peers) can claim, execute, complete, or fail with lease semantics — while activity-core stays when/what/where only.

Non-goals: execute domain work in Temporal activities; use issue-core or Forgejo as the claim queue; invent Gitea support.

Architecture (target)

Temporal schedule / trigger
  → resolve context (e.g. fi_brief_status)
  → rules produce TaskSpec(s)
  → INSERT ops_run (open) + optional activity_task_spawn progress
  → rein-aharness claim loop
  → complete/fail + domain completion event (fi_daily_brief, …)

Tasks

T01 — Spec ops_run model and API

id: ACTIVITY-WP-0026-T01
status: done
priority: high
state_hub_task_id: "d2f92ac2-d900-43d8-83ae-62e77d7467d4"

Document in docs/ops-run-queue.md:

Field Notes
id UUIDv7
activity_definition_id FK
idempotency_key unique; e.g. {def}:{date} or hash of spawn key
target_repo string
title, description from TaskSpec
labels JSON array
priority
state open | claimed | succeeded | failed | expired
claim_owner worker identity
lease_until timestamptz
attempt int
source_type, source_id, triggering_event_id audit
approach_hint optional from definition/rule
result JSON completion metadata
created_at, updated_at

API (REST on actcore-api):

  • POST /ops-runs/claim body: { worker_id, labels?, limit? } → runs
  • POST /ops-runs/{id}/heartbeat extend lease
  • POST /ops-runs/{id}/complete / fail
  • GET /ops-runs filter by state, definition, since

Auth: same operator/worker posture as existing admin APIs (document; prefer service credential for harness, SSO for humans later).

Done when: spec reviewed against ACT-ADR-005; OpenAPI-ready field list.


T02 — Schema migration + ORM

id: ACTIVITY-WP-0026-T02
status: done
priority: high
state_hub_task_id: "65d0d28f-0be6-4ae5-9e12-a051ccebbb36"

Alembic migration for ops_runs (+ indexes on state, lease_until, idempotency_key unique). SQLAlchemy model. Unit tests for constraints.

Done when: migrate up/down clean on dev; model tests green.


T03 — Emit path: create ops_run on TaskSpec emit

id: ACTIVITY-WP-0026-T03
status: done
priority: high
state_hub_task_id: "1615936e-e0a4-4221-8b93-ec7938bd523b"

On successful rule emit (internal fleet path):

  1. Upsert/insert ops_run with idempotency (duplicate key → no second open row).
  2. Keep dual-write activity_task_spawn progress for transition period.
  3. Still write task_spawn_log audit.
  4. Never require Forgejo / issue-core rest for this path.

Default sink remains state-hub for progress; ops_run is additional primary for claim.

Done when: schedule fire or /trigger produces open ops_run for FI and Binky-style definitions; tests with mocked sink.


T04 — Claim / lease / expire worker helpers

id: ACTIVITY-WP-0026-T04
status: done
priority: high
state_hub_task_id: "57cdd0ce-2d54-4148-89e2-9d89c33d7f8a"

Implement claim with SELECT … FOR UPDATE SKIP LOCKED (or equivalent) and lease TTL (config: e.g. 15m). Expire job or on-claim sweep: claimed past lease_untilopen (retry) or expired after max attempts.

Done when: concurrent claim tests; lease expiry documented.


T05 — Ops visibility: list + SLA signals

id: ACTIVITY-WP-0026-T05
status: done
priority: medium
state_hub_task_id: "08f53f8b-6a17-4a21-9639-88f6924a7c1a"
  • Extend /ops/automations/status (or sibling) with open/claimed/failed counts.
  • Signal: “spawned/open without complete by SLA” (config, default 1h for daily).
  • Document in runbook.

Done when: operator can see stuck ops_runs without SQL.


T06 — Contract + consumer guide

id: ACTIVITY-WP-0026-T06
status: done
priority: medium
state_hub_task_id: "f8ca5ab8-3343-4edb-9ae8-fdbc90e17aae"

Update:

  • docs/task-emission-consumer-contract.md — claim ops_run, not issue-core
  • docs/recurring-automations-playbook.md — reference ACT-ADR-005
  • docs/issue-core-emission-boundary.md — ops_run is not issue-core
  • Use Forgejo naming only (no Gitea product references)

Done when: REIN-A-0002 can implement against the contract without guesswork.


T07 — Railiance rollout + dual-path flag

id: ACTIVITY-WP-0026-T07
status: todo
priority: medium
state_hub_task_id: "b1ce221b-edb2-42ed-91a1-e9f144a58d1e"

Deploy notes + executable checklist (docs only until smoke green):

docs/deploy-ops-run-queue-railiance.md

Manifest prep (landed with this notes commit):

  • OPS_RUN_* keys in k8s/railiance/20-runtime.yaml ConfigMap
  • Checklist: image → migrate 0007 → rollout → FI trigger smoke → manual claim
  • Dual-path residual documented (keep host timers; REIN-A-0002 next)
  • Operator executes checklist on railiance (still open)
  • Prod smoke boxes ticked in deploy doc → mark this task done

Done when: prod smoke checklist green on railiance; flag live.

Acceptance

  • ACT-ADR-005 referenced in SCOPE gaps (G2 disposition → this WP)
  • ops_run durable + claimable without Forgejo
  • Emit dual-write progress for transition
  • Docs use Forgejo-only language for self-hosted forge
  • REIN-A-0002 unblocked (contract in docs/ops-run-queue.md + consumer contract)

T07 remaining: execute docs/deploy-ops-run-queue-railiance.md on railiance (image + migrate + smoke). Notes/checklist + ConfigMap flags are in-repo.

Out of scope

  • rein-aharness claim loop (REIN-A-0002)
  • State Hub full write path for claim (read projection = STATE-WP-0078)
  • issue-core internal SQLite “fake queue”
  • Gitea compatibility