Skip to content

Conversation

@jason-lynch
Copy link
Member

@jason-lynch jason-lynch commented Jan 14, 2026

Summary

Adds new endpoints to track host-scoped tasks:

  • list-host-tasks
  • get-host-task
  • get-host-task-log

As well as a new endpoint to list tasks across all scopes:

  • list-tasks

Testing

Nothing produces host tasks in this PR (will be added in a subsequent PR), but you should be able to see database tasks with the list-tasks endpoint.

PLAT-347

Summary by CodeRabbit

Release Notes

  • New Features

    • Added host-scoped task management endpoints: list host tasks, retrieve host task details, and access host task logs.
    • Added global task listing endpoint supporting filtering by database or host scope with pagination and sorting capabilities.
    • Updated client methods to distinguish between database and host task operations for improved clarity.
  • Documentation

    • Updated task and logs guide with comprehensive examples for the new host task endpoints and cross-scope task querying.

✏️ Tip: You can customize this high-level summary in your review settings.

@jason-lynch jason-lynch force-pushed the feat/PLAT-347/add-scope-to-tasks branch from 9ff3ccb to 83955e8 Compare January 15, 2026 13:51
@jason-lynch jason-lynch force-pushed the feat/PLAT-347/new-task-endpoints branch from 4c7d9b7 to f43d9aa Compare January 15, 2026 13:51
@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This change introduces host-scoped task management endpoints alongside a cross-scope task listing endpoint to the control-plane API. New capabilities include listing and retrieving host-specific tasks, accessing host task logs, and querying tasks across database or host scopes. Client interfaces, single and multi-server implementations, and server-side API handlers are added. Task-related helper methods are renamed to clarify database versus host scope distinction.

Changes

Cohort / File(s) Summary
API Design & Types
api/apiv1/design/api.go, api/apiv1/design/task.go
Added four new API method definitions: list-host-tasks, get-host-task, get-host-task-log, and list-tasks (cross-scope). Introduced ListHostTasksResponse and ListTasksResponse types with example payloads.
Client Interface
client/interface.go
Added public methods ListTasks, ListHostTasks, GetHostTask, GetHostTaskLog. Renamed generic task helpers WaitForTaskWaitForDatabaseTask, FollowTaskFollowDatabaseTask, and added host-specific variants WaitForHostTask, FollowHostTask.
Single-Server Client
client/single.go
Implemented new public methods for host and cross-scope task operations. Introduced generic waitForTask helper and taskEnded map for terminal status tracking. Refactored polling logic with scope-specific implementations for database and host tasks.
Multi-Server Client
client/multi.go
Added pass-through methods for all new task operations. Updated task-waiting and task-following logic to route to database/host-specific server methods.
Server API Handlers
server/internal/api/apiv1/post_init_handlers.go, server/internal/api/apiv1/pre_init_handlers.go
Implemented ListHostTasks, GetHostTask, GetHostTaskLog, ListTasks handlers in both post-init (with business logic) and pre-init (stub implementations returning ErrUninitialized).
Server Conversion Utilities
server/internal/api/apiv1/convert.go
Added helper functions: taskListOptionsFromHost, taskLogOptionsFromHost, taskListOptionsFromGeneric, and parseScope to validate and convert host and generic task payloads into internal task options.
Documentation
docs/using/tasks-logs.md
Expanded task documentation with new sections for host-scoped task operations. Added cross-scope task listing endpoint documentation and multiple curl examples for filtering by scope and entity.
Developer Tools
hack/dev-env.zsh
Refactored interactive task-following helpers: added _choose-scope() and _choose-host() functions. Updated cp-follow-task() to use scope/entity-id model instead of database-id-only model.
Tests & Changelog
e2e/cancel_task_test.go, e2e/database_test.go, changes/unreleased/Added-20260114-162946.yaml
Updated task waiter calls from WaitForTask to WaitForDatabaseTask. Added changelog entry documenting new host-scoped and cross-scope task endpoints.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

Through hosts and databases, tasks now roam free, 🐰
New endpoints branching out structurally,
Scope-aware and scurrying with care,
Four fresh paths—completion everywhere!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description includes summary, testing notes, and issue link, but is missing sections for Changes (bulleted list), Checklist, and Notes for Reviewers per the template. Add a Changes section with bulleted list of modifications, complete the Checklist, and optionally add Notes for Reviewers to improve clarity and align with repository standards.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: new task endpoints' is concise, follows Conventional Commits format, and accurately describes the main change of adding multiple new task-related API endpoints.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jason-lynch jason-lynch force-pushed the feat/PLAT-347/new-task-endpoints branch 2 times, most recently from 85c8902 to f5b0ba8 Compare January 15, 2026 14:03
@jason-lynch jason-lynch force-pushed the feat/PLAT-347/add-scope-to-tasks branch 2 times, most recently from 7391dab to 53678c0 Compare January 15, 2026 17:35
@jason-lynch jason-lynch force-pushed the feat/PLAT-347/new-task-endpoints branch from f5b0ba8 to e2c5ecc Compare January 15, 2026 17:36
@jason-lynch jason-lynch force-pushed the feat/PLAT-347/add-scope-to-tasks branch from 53678c0 to 8619be9 Compare January 15, 2026 21:42
@jason-lynch jason-lynch force-pushed the feat/PLAT-347/new-task-endpoints branch 2 times, most recently from ff7f98c to 57c9324 Compare January 15, 2026 21:50
@jason-lynch jason-lynch force-pushed the feat/PLAT-347/add-scope-to-tasks branch from 8619be9 to baedea3 Compare January 15, 2026 21:56
@jason-lynch jason-lynch force-pushed the feat/PLAT-347/new-task-endpoints branch from 57c9324 to bdd4154 Compare January 15, 2026 21:56
@jason-lynch
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@e2e/cancel_task_test.go`:
- Around line 64-67: The test calls fixture.Client.WaitForDatabaseTask and
immediately uses final_task in assertions without checking err; modify the test
around the WaitForDatabaseTask call (the variables final_task, err, and the
GetDatabaseTaskPayload using cancelation_task.TaskID) to assert or fail
immediately when err != nil (e.g., t.Fatalf or require.NoError) so the test
stops on waiter failures before accessing final_task.

In `@hack/dev-env.zsh`:
- Around line 548-555: The code treats JSON null strings as valid because jq -r
returns "null"; update the three jq extractions (scope, entity_id, task_id) to
convert JSON null to an empty string (e.g., use the jq "// empty" or equivalent)
so that nulls fail the existing -z check, or alternatively add a check that
treats the literal "null" as empty (test for == "null"). Change the lines that
set scope, entity_id, and task_id (the variables named scope, entity_id,
task_id) to use that null-to-empty handling so the subsequent if [[ -z ... ]]
correctly rejects missing fields.
- Around line 72-96: The scope selection calls jq on a plain string causing
parse errors; in _choose-scope, stop piping scope_choice through jq—set scope to
the chosen string (trim whitespace/newlines) and log "using scope ${scope}"
instead of trying to parse JSON. In _choose-host, change the log message from
"using database ${host_id}" to "using host ${host_id}" (host_id is correctly
extracted with jq -r '.id') so the label matches the selection.
🧹 Nitpick comments (1)
client/single.go (1)

246-322: Consider extracting shared logic to reduce duplication.

FollowDatabaseTask and FollowHostTask share nearly identical structure—the only differences are the payload types and the GetXxxTaskLog method called. While this duplication is acceptable for now, consider a similar callback-based refactor (like waitForTask) if more scope-specific follow methods are added in the future.

♻️ Possible future refactor using generics
// A generic follow helper could look like:
func followTask[P any](
    ctx context.Context,
    req P,
    cloneReq func(P, *string) P,
    getLog func(context.Context, P) (*api.TaskLog, error),
    handler func(e *api.TaskLogEntry),
) error {
    // ... shared polling logic
}

This is optional and could be deferred until there's a third scope or more complexity.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between baedea3 and bdd4154.

⛔ Files ignored due to path filters (17)
  • api/apiv1/gen/control_plane/client.go is excluded by !**/gen/**
  • api/apiv1/gen/control_plane/endpoints.go is excluded by !**/gen/**
  • api/apiv1/gen/control_plane/service.go is excluded by !**/gen/**
  • api/apiv1/gen/http/cli/control_plane/cli.go is excluded by !**/gen/**
  • api/apiv1/gen/http/control_plane/client/cli.go is excluded by !**/gen/**
  • api/apiv1/gen/http/control_plane/client/client.go is excluded by !**/gen/**
  • api/apiv1/gen/http/control_plane/client/encode_decode.go is excluded by !**/gen/**
  • api/apiv1/gen/http/control_plane/client/paths.go is excluded by !**/gen/**
  • api/apiv1/gen/http/control_plane/client/types.go is excluded by !**/gen/**
  • api/apiv1/gen/http/control_plane/server/encode_decode.go is excluded by !**/gen/**
  • api/apiv1/gen/http/control_plane/server/paths.go is excluded by !**/gen/**
  • api/apiv1/gen/http/control_plane/server/server.go is excluded by !**/gen/**
  • api/apiv1/gen/http/control_plane/server/types.go is excluded by !**/gen/**
  • api/apiv1/gen/http/openapi.json is excluded by !**/gen/**
  • api/apiv1/gen/http/openapi.yaml is excluded by !**/gen/**
  • api/apiv1/gen/http/openapi3.json is excluded by !**/gen/**
  • api/apiv1/gen/http/openapi3.yaml is excluded by !**/gen/**
📒 Files selected for processing (13)
  • api/apiv1/design/api.go
  • api/apiv1/design/task.go
  • changes/unreleased/Added-20260114-162946.yaml
  • client/interface.go
  • client/multi.go
  • client/single.go
  • docs/using/tasks-logs.md
  • e2e/cancel_task_test.go
  • e2e/database_test.go
  • hack/dev-env.zsh
  • server/internal/api/apiv1/convert.go
  • server/internal/api/apiv1/post_init_handlers.go
  • server/internal/api/apiv1/pre_init_handlers.go
🧰 Additional context used
📓 Path-based instructions (4)
server/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

server/**/*.go: Use samber/do injector for dependency injection; each package should have a Provide() function that registers dependencies
Use structured JSON logging with zerolog throughout the codebase, with pretty-printing enabled in dev mode
Domain-specific errors should be defined in each package; API errors should be mapped to HTTP status codes via Goa

Files:

  • server/internal/api/apiv1/convert.go
  • server/internal/api/apiv1/post_init_handlers.go
  • server/internal/api/apiv1/pre_init_handlers.go
server/internal/api/apiv1/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Implement generated Goa service interface methods in server/internal/api/apiv1/ after regenerating code

Files:

  • server/internal/api/apiv1/convert.go
  • server/internal/api/apiv1/post_init_handlers.go
  • server/internal/api/apiv1/pre_init_handlers.go
e2e/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

E2E tests should use build tag //go:build e2e_test and place test fixtures in e2e/fixtures/

Files:

  • e2e/database_test.go
  • e2e/cancel_task_test.go
api/apiv1/design/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

API endpoints should be defined using Goa's DSL in api/apiv1/design/ with separate files for domain-specific types (database.go, host.go, cluster.go), then regenerated with make -C api generate

Files:

  • api/apiv1/design/api.go
  • api/apiv1/design/task.go
🧠 Learnings (1)
📚 Learning: 2026-01-14T16:43:14.333Z
Learnt from: CR
Repo: pgEdge/control-plane PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-14T16:43:14.333Z
Learning: Applies to api/apiv1/design/**/*.go : API endpoints should be defined using Goa's DSL in `api/apiv1/design/` with separate files for domain-specific types (database.go, host.go, cluster.go), then regenerated with `make -C api generate`

Applied to files:

  • api/apiv1/design/api.go
  • api/apiv1/design/task.go
  • client/single.go
🧬 Code graph analysis (8)
server/internal/api/apiv1/convert.go (4)
api/apiv1/gen/control_plane/service.go (3)
  • ListHostTasksPayload (691-700)
  • GetHostTaskLogPayload (520-529)
  • ListTasksPayload (717-728)
server/internal/task/task_store.go (2)
  • TaskListOptions (55-64)
  • SortOrder (44-44)
server/internal/task/task_log_store.go (1)
  • TaskLogOptions (73-76)
server/internal/task/task.go (3)
  • Scope (13-13)
  • ScopeDatabase (20-20)
  • ScopeHost (21-21)
e2e/database_test.go (1)
api/apiv1/gen/control_plane/service.go (1)
  • GetDatabaseTaskPayload (504-509)
server/internal/api/apiv1/post_init_handlers.go (5)
api/apiv1/gen/control_plane/service.go (4)
  • ListHostTasksPayload (691-700)
  • ListHostTasksResponse (704-706)
  • Task (938-965)
  • TaskLog (969-984)
api/apiv1/design/task.go (3)
  • ListHostTasksResponse (314-331)
  • Task (7-79)
  • TaskLog (101-262)
server/internal/task/task.go (4)
  • Task (67-83)
  • TaskLog (246-253)
  • Status (45-45)
  • Scope (13-13)
server/internal/api/apiv1/errors.go (1)
  • ErrInvalidTaskID (33-33)
server/internal/task/task_store.go (2)
  • TaskListOptions (55-64)
  • SortOrder (44-44)
e2e/cancel_task_test.go (2)
client/interface.go (1)
  • Client (9-44)
api/apiv1/gen/control_plane/service.go (1)
  • GetDatabaseTaskPayload (504-509)
server/internal/api/apiv1/pre_init_handlers.go (3)
api/apiv1/gen/control_plane/service.go (8)
  • ListHostTasksPayload (691-700)
  • ListHostTasksResponse (704-706)
  • GetHostTaskPayload (533-538)
  • Task (938-965)
  • GetHostTaskLogPayload (520-529)
  • TaskLog (969-984)
  • ListTasksPayload (717-728)
  • ListTasksResponse (732-734)
server/internal/api/apiv1/errors.go (1)
  • ErrUninitialized (32-32)
server/internal/task/task.go (2)
  • Task (67-83)
  • TaskLog (246-253)
client/multi.go (3)
api/apiv1/gen/control_plane/service.go (9)
  • ListTasksPayload (717-728)
  • ListTasksResponse (732-734)
  • ListHostTasksPayload (691-700)
  • ListHostTasksResponse (704-706)
  • GetHostTaskPayload (533-538)
  • Task (938-965)
  • GetHostTaskLogPayload (520-529)
  • TaskLog (969-984)
  • TaskLogEntry (986-993)
api/apiv1/design/task.go (5)
  • ListTasksResponse (333-361)
  • ListHostTasksResponse (314-331)
  • Task (7-79)
  • TaskLog (101-262)
  • TaskLogEntry (81-99)
server/internal/task/task.go (2)
  • Task (67-83)
  • TaskLog (246-253)
api/apiv1/design/task.go (2)
server/internal/task/task.go (2)
  • Type (24-24)
  • Task (67-83)
api/apiv1/gen/control_plane/service.go (1)
  • Task (938-965)
client/single.go (5)
client/enums.go (3)
  • TaskStatusCompleted (86-86)
  • TaskStatusCanceled (90-90)
  • TaskStatusFailed (87-87)
server/internal/resource/resource.go (1)
  • Context (84-88)
api/apiv1/gen/control_plane/service.go (8)
  • ListTasksPayload (717-728)
  • ListTasksResponse (732-734)
  • ListHostTasksResponse (704-706)
  • GetHostTaskPayload (533-538)
  • Task (938-965)
  • GetHostTaskLogPayload (520-529)
  • TaskLog (969-984)
  • TaskLogEntry (986-993)
api/apiv1/design/task.go (5)
  • ListTasksResponse (333-361)
  • ListHostTasksResponse (314-331)
  • Task (7-79)
  • TaskLog (101-262)
  • TaskLogEntry (81-99)
server/internal/task/task.go (3)
  • Task (67-83)
  • TaskLog (246-253)
  • Status (45-45)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (18)
server/internal/api/apiv1/convert.go (1)

795-867: Nice helper coverage for host/generic task options.
Validation and parsing mirror the database helpers and keep behavior consistent.

api/apiv1/design/task.go (1)

313-361: Clear response types for new task listings.
Examples are consistent with the Task schema and make the intent obvious.

api/apiv1/design/api.go (1)

529-678: Endpoints align with existing task API patterns.
Payloads, result types, and error models look consistent.

server/internal/api/apiv1/post_init_handlers.go (2)

1087-1152: Host task handlers follow established database-task patterns.
Looks consistent in validation and data retrieval.


1154-1195: No changes needed — the endpoint correctly returns tasks across all scopes when scope is omitted.

When req.Scope is nil, taskListOptionsFromGeneric returns an empty scope string. The storage layer's EntityPrefix function with an empty scope produces /tasks_v2/ (empty strings are filtered by Go's path.Join), which serves as a prefix for all scope-specific tasks. The etcd range query matches all tasks under this prefix, returning results from both database and host scopes. This behavior is intentional and documented in the Goa API design (see ListTasksResponse example showing mixed-scope results).

Likely an incorrect or invalid review comment.

server/internal/api/apiv1/pre_init_handlers.go (1)

274-288: Pre-init stubs are consistent with existing behavior.
Returning ErrUninitialized keeps the contract clear.

changes/unreleased/Added-20260114-162946.yaml (1)

1-3: Changelog entry looks good.

Clear and concise summary of the new API endpoints.

e2e/database_test.go (1)

339-343: Waiter update is correct.

The database-scoped waiter matches the new API surface.

docs/using/tasks-logs.md (1)

142-151: No action needed. The endpoint path documented at /v1/hosts/{host_id}/tasks/{task_id}/logs matches the actual API implementation in the codebase across all route handlers, service definitions, and OpenAPI specs. Users will not receive 404s.

client/interface.go (2)

25-31: LGTM! Well-structured API method additions.

The new task endpoints (ListTasks, ListHostTasks, GetHostTask, GetHostTaskLog) are correctly positioned in the interface and use the appropriate generated payload/response types, aligning with the PR objective of adding host-scoped task management.


40-43: Good separation of database vs. host task helpers.

The renamed WaitForDatabaseTask/FollowDatabaseTask and new WaitForHostTask/FollowHostTask methods provide clear scope-specific APIs, improving clarity over the previous generic WaitForTask/FollowTask names.

client/multi.go (3)

210-216: LGTM! Consistent pass-through implementation.

The ListTasks method follows the established pattern of delegating to a live server, consistent with other read operations in this file.


242-264: LGTM! Host task methods follow the established pattern.

ListHostTasks, GetHostTask, and GetHostTaskLog are implemented consistently with the existing database task methods, correctly delegating to the live server.


313-343: LGTM! Wait and follow helpers correctly delegate to SingleServerClient.

The renamed WaitForDatabaseTask/FollowDatabaseTask and new WaitForHostTask/FollowHostTask methods properly delegate to the underlying SingleServerClient implementation where the actual polling logic resides.

client/single.go (4)

18-22: LGTM! Terminal status map correctly excludes transitional states.

The taskEnded map correctly identifies completed, canceled, and failed as terminal states. Notably, canceling is correctly excluded since it's a transitional state (the task is still in progress of being canceled).


72-75: LGTM! New endpoint wiring is complete.

All four new endpoints (ListHostTasks, GetHostTask, GetHostTaskLog, ListTasks) are properly wired to the generated client methods.


145-178: LGTM! New API methods follow established patterns.

ListTasks, ListHostTasks, GetHostTask, and GetHostTaskLog are implemented consistently with the existing database task methods, properly using translateErr for error handling.


195-229: Good refactor extracting common polling logic.

The waitForTask helper with a getTask callback cleanly abstracts the polling logic, allowing WaitForDatabaseTask and WaitForHostTask to share the implementation while remaining type-safe through their specific payload types.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@jason-lynch jason-lynch force-pushed the feat/PLAT-347/new-task-endpoints branch from bdd4154 to e77c094 Compare January 15, 2026 23:03
@jason-lynch jason-lynch force-pushed the feat/PLAT-347/add-scope-to-tasks branch from baedea3 to 1ad0c8b Compare January 16, 2026 14:22
Adds endpoints to get/list host tasks and to get host task logs.

PLAT-347
Adds an endpoint to list tasks across all entities.

PLAT-347
Updates `cp-follow` task to support host-scoped tasks.

PLAT-347
Updates `task-logs.md` document with usage examples for the new
endpoints and adds a changelog entry for the new endpoints.

PLAT-347
@jason-lynch jason-lynch force-pushed the feat/PLAT-347/new-task-endpoints branch from e77c094 to 61a0c96 Compare January 16, 2026 14:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants