Skip to content

feat(executions): add worker_id + status__in filters and oldest_claimed_at#48

Closed
mikemolinet wants to merge 3 commits into
mainfrom
feat/executions-worker-id-filter
Closed

feat(executions): add worker_id + status__in filters and oldest_claimed_at#48
mikemolinet wants to merge 3 commits into
mainfrom
feat/executions-worker-id-filter

Conversation

@mikemolinet
Copy link
Copy Markdown
Collaborator

Summary

Per CTO ask CTO-CUEAPI-EXEC-WORKER-FILTER — unblocks CMA's Surface 6.7 menubar pending-exec counter that wants to fetch pending,delivering,retry_ready for one worker in a single round trip.

Three additive surface bumps on GET /v1/executions:

  • worker_id= — filters to executions claimed by that worker (Execution.claimed_by_worker == worker_id).
  • status__in= — comma-separated multi-status filter via Execution.status.in_([...]). Mutex with status=; passing both returns 400 conflicting_filters.
  • oldest_claimed_at — new response field, earliest claimed_at over the filtered set as ISO-8601 string. Null when count=0 so callers can render "oldest pending: 5m" without a follow-up query.

Auth scoping unchanged — all new filters apply AFTER the existing Cue.user_id == user.id join.

Test plan

  • tests/test_execution_parity.py::TestListExecutions — 7/7 (4 pre-existing + 3 new):
    • test_filter_by_worker_id — scoping + oldest_claimed_at correctness across two workers
    • test_status_in_returns_union — union behavior + 400 mutex with status=
    • test_oldest_claimed_at_null_when_empty — null when filtered set is empty
  • Full executions suite: 59/59 (test_execution_parity + test_execution_pagination + test_worker_transport)

🤖 Generated with Claude Code

…ed_at

Adds three additive surface bumps on `GET /v1/executions` to unblock
pending-execution counter UIs (e.g. the menubar counter that wants to
fetch `pending,delivering,retry_ready` for one worker in a single
round trip):

- `worker_id=` query param filters to executions claimed by that worker
  (`Execution.claimed_by_worker == worker_id`).
- `status__in=` comma-separated multi-status filter using
  `Execution.status.in_([...])`. Mutex with `status=`; passing both
  returns 400 `conflicting_filters`.
- `oldest_claimed_at` response field is the earliest `claimed_at` over
  the filtered set, ISO-8601 string. Null when the result count is 0
  so callers can render "oldest pending: 5m" without a follow-up
  query.

Auth scoping unchanged — every new filter applies AFTER the existing
`Cue.user_id == user.id` join, so multi-tenant leak surface is
identical to the pre-existing `cue_id`/`status`/`outcome_state`
filters.

Tests: 3 new in TestListExecutions (worker_id scoping +
oldest_claimed_at value, status__in union + mutex 400, null
oldest_claimed_at on empty filtered set). 59/59 in the executions
suite green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

Parity check

This PR modifies files tracked in parity-manifest.json:

  • app/routers/executions.py

Please confirm one of the following in a reply or PR description update:

  1. The equivalent change has been applied to the private cueapi monorepo. Link the PR.
  2. This change is OSS-only and does not need porting. Briefly explain why (e.g. "fixes a bug that only exists in the OSS build").
  3. A follow-up issue has been filed to port the reverse direction. Link the issue.

This is a soft check — it does not block merge. The goal is visibility, not friction. See HOSTED_ONLY.md for the open-core policy.

@govindkavaturi-art govindkavaturi-art enabled auto-merge (squash) May 6, 2026 00:21
@mikemolinet
Copy link
Copy Markdown
Collaborator Author

Closing as stale — branch diverged from main by ~8872 deletions across 57 files. Rebase infeasible.

Feature is still needed: app/routers/executions.py list_executions endpoint (line 32+) accepts cue_id, status, outcome_state, limit, offset — but does NOT accept worker_id or status__in, and does not surface oldest_claimed_at.

Next step: re-port as fresh PR against current main HEAD (f9ec4ea).

Branch retained for reference.

auto-merge was automatically disabled May 11, 2026 15:33

Pull request was closed

mikemolinet added a commit that referenced this pull request May 11, 2026
…parity port of cueapi/cueapi#623) (#77)

Re-port of closed [PR #46](#46) which was on a stale base ~8900 deletions behind main. Fresh against current main HEAD.

Closes §13 / Phase 12.1.7 — messages-side complement to the cue-fire send_at shipped in PR #618 (which still needs its own re-port).

## What lands

- **alembic/versions/030_message_send_at.py** (renumbered from private's 047)
  Adds `messages.send_at TIMESTAMPTZ NULL` + partial index
  `ix_messages_send_at` (WHERE send_at IS NOT NULL) built CONCURRENTLY
  so the index creation doesn't take an ACCESS EXCLUSIVE lock on
  the messages table during deploy. Existing rows default to NULL =
  "send now".
- **app/models/message.py** — adds `send_at` Column.
- **app/schemas/message.py** — `send_at: Optional[datetime]` on
  MessageCreate + MessageResponse.
- **app/routers/messages.py** — passes `send_at=body.send_at` into
  `create_message`.
- **app/services/inbox_service.py** — gates inbox query AND
  queued→delivered transition UPDATE with
  `send_at IS NULL OR send_at <= now()`. Scheduled messages are
  invisible until their time; the atomic poll-fetch transition
  skips them too.
- **app/services/message_service.py** — `create_message` plumbs
  `send_at` into both `Message.send_at` and
  `DispatchOutbox.scheduled_at`. Past timestamps are forgiving
  fallback (treated as send-now). `to_response_dict` surfaces the
  persisted value.
- **tests/test_message_send_at.py** — 7 new tests verbatim from
  private cueapi covering all 7 semantic paths (omitted,
  future-invisible, outbox-scheduled, past-fallback, becomes-visible-
  after-pass, sender-view-shows-it, invalid-timestamp).
- **parity-manifest.json** — new entry for migration 030 under
  `message-send-at-port (private #623)`.

## Wire format

`send_at` flows in the BODY of `POST /v1/messages` (server contract:
`MessageCreate.send_at`). Same shape as cue-fire `send_at` (PR #618).
NULL = send now (default). Future timestamp = inbox-gate +
DispatchOutbox.scheduled_at. Past timestamp = forgiving send-now.

## Tests

7/7 new tests pass locally. Full local suite: 836 passed + 18
xfailed (pre-existing) + 3 skipped. Zero regressions.

## Sibling ports

- cli, mcp, python, action sides shipped via session 2 (2026-05-10):
  cueapi-cli #48, cueapi-mcp #33, cueapi-python (private), cueapi-action #12.
  This is the cueapi-core (OSS server) side that was still missing.

## Re-port note

Re-port of closed PR #46. That branch was ~8900 deletions behind main;
fresh port against current main HEAD (after PR #74 + #75 merged earlier
in this session).
mikemolinet added a commit that referenced this pull request May 11, 2026
…ed_at on list endpoint (#79)

Re-port of closed [PR #48](#48) which was on a stale base ~8870 deletions behind main. Fresh against current main HEAD via direct patch from the old branch's commit (c05518c).

Adds query-side enrichment to ``GET /v1/executions``:

- ``worker_id=`` — filter to executions claimed by a specific worker
  (Execution.claimed_by_worker)
- ``status__in=foo,bar,baz`` — comma-separated multi-status filter.
  Mutex with ``status=``; 400 conflicting_filters if both passed.
- Response gains ``oldest_claimed_at`` — earliest ``claimed_at`` over
  the filtered set, or null when count=0. Unblocks dashboard/menubar
  "oldest pending: 5m" rendering without a follow-up query.

## Use cases

- **Menubar pending counter**: fetch ``pending,delivering,retry_ready``
  in one round trip (status__in), get total + oldest_claimed_at to
  render "3 in flight, oldest claimed 8m ago".
- **Worker health dashboard**: filter by worker_id to scope to one
  worker's claims; see how stale their oldest claim is.

## Tests

3 new tests in TestListExecutions:
- worker_id scoping + oldest_claimed_at value reflects earliest
  claimed_at over filtered set
- status__in union + status/status__in mutex 400
- null oldest_claimed_at on empty filtered set

31/31 in test_execution_parity.py green. Full local suite: zero
regressions.

## Re-port note

Re-port of closed PR #48 (commit c05518c). Branch was ~8870 deletions
behind main; fresh against current main after PR #74/#75/#76/#77/#78
merged earlier in this session. Patch applied cleanly from c05518c
to current main — the patch only touches list_executions endpoint,
which has remained additive (cueapi-core added outcome_state filter
since the branch was cut; this PR is compatible).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant