activity-core/docs/ops-run-queue.md
tegwick 15eb3a2066
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 52s
Implement ACTIVITY-WP-0026 ops_run claim queue (T01–T06).
Add durable claimable ops_runs table, emit dual-write on TaskSpec, REST
claim/lease/complete/fail API, ops status visibility, and consumer docs
aligned with ACT-ADR-005. T07 railiance rollout remains deploy-side.
2026-08-03 19:22:50 +02:00

3.9 KiB

Ops run claim queue

Status: implemented (ACTIVITY-WP-0026 code path; railiance rollout = T07)
Architecture: ACT-ADR-005

Durable, claimable work instances for scheduled / automation runs. Not a workplan task file. Not an issue-core or Forgejo ticket.

Model

Field Type Notes
id UUID Primary key (uuid4; UUIDv7 optional later)
activity_definition_id UUID FK → activity_definitions
idempotency_key text Unique; default {activity_id}:{source_id}:{triggering_event_id}
target_repo text From TaskSpec
title text
description text
labels JSONB array e.g. ["automated","research-brief"]
priority text low | medium | high
state text open | claimed | succeeded | failed | expired
claim_owner text nullable Worker identity
lease_until timestamptz nullable Claim lease deadline
attempt int Starts at 0; incremented on each claim
source_type text rule | instruction
source_id text Rule id
triggering_event_id text Event or workflow key
approach_hint text nullable Optional from rule
result JSONB Completion metadata
created_at / updated_at timestamptz

API (actcore-api)

Method Path Role
GET /ops-runs List/filter
GET /ops-runs/{id} One row
POST /ops-runs/claim Claim open runs (lease)
POST /ops-runs/{id}/heartbeat Extend lease
POST /ops-runs/{id}/complete succeeded
POST /ops-runs/{id}/fail failed (+ optional reopen)
POST /ops-runs/expire-leases Reopen or expire stale claims

Claim body

{
  "worker_id": "rein-aharness@railiance01",
  "labels": ["automated"],
  "labels_mode": "any",
  "limit": 1,
  "lease_seconds": 900
}
  • labels_mode: any (default) — run must contain at least one listed label; all — run must contain every listed label; omit labels to claim any open run.
  • Claim uses FOR UPDATE SKIP LOCKED for concurrency safety.
  • Stale claims (state=claimed and lease_until < now()) are reopened before select.

Complete / fail body

{ "result": { "path": "briefs/…", "ok": true }, "worker_id": "…" }
{ "error": "llm timeout", "worker_id": "…", "reopen": false }

If reopen: true and attempt < max_attempts (env OPS_RUN_MAX_ATTEMPTS, default 3), state returns to open; else failed.

Emit path

On emit_tasks (when OPS_RUN_QUEUE_ENABLED is truthy, default true):

  1. Insert ops_run with state=open (idempotent on unique key).
  2. Dual-write existing IssueSink (state-hub progress by default).
  3. Write task_spawn_log audit as today.

Never requires Forgejo or issue-core for the claim path.

Auth

  • Worker: ACTIVITY_CORE_WORKER_TOKEN via X-Worker-Token or Authorization: Bearer (same value accepted on claim/complete/fail/heartbeat).
  • Operator: existing ops SSO / ACTIVITY_CORE_OPERATOR_TOKEN for list/status.
  • Local dev: ACTIVITY_CORE_OPS_ALLOW_UNAUTH_MUTATIONS=1 when no tokens set.

Env

Variable Default Meaning
OPS_RUN_QUEUE_ENABLED true Create ops_run on emit
OPS_RUN_LEASE_SECONDS 900 Default claim lease
OPS_RUN_MAX_ATTEMPTS 3 Fail permanently after N claims
ACTIVITY_CORE_WORKER_TOKEN unset Harness claim credential

Consumer (rein-aharness)

See REIN-A-0002. Claim loop → approach table → execute → complete + domain completion event (fi_daily_brief, etc.).

Not this queue

Concern Home
Multi-day engineering tasks Workplan files + State Hub
External tracker tickets issue-core → Forgejo (optional projection)
Schedule truth Temporal + activity definitions