Skip to content

refactor(store): wave B.14 — action repo (#271)#272

Merged
PaulDotterer merged 1 commit into
mainfrom
feat/271-action-repo
May 15, 2026
Merged

refactor(store): wave B.14 — action repo (#271)#272
PaulDotterer merged 1 commit into
mainfrom
feat/271-action-repo

Conversation

@PaulDotterer

@PaulDotterer PaulDotterer commented May 15, 2026

Copy link
Copy Markdown
Contributor

Summary

`ActionRepo` — foundation of the action-chain cluster. ActionSet / Definition / Execution / Assignment follow in subsequent sub-waves (the cluster is too big for one PR). Branches off main directly.

Methods

  • `Get(id)` / `List(filter)` / `Count(filter)` — `ActionTypeFilter` + `UnassignedOnly` shared between List and Count
  • `NamesByIDs(ids)` — bulk name lookup for response builders
  • `UpdateSignature(p)` — CA key-rotation rewrite (the only non-event write the action domain owns)

`Params` / `ParamsCanonical` / `Schedule` stay as `json.RawMessage` at the boundary per the JSONB normalize plan; `Signature` stays `[]byte` (already opaque at the wire).

Call sites migrated (~20)

  • `action_crud.go` + `action_handler.go` — full CRUD + `actionToProto` / `persistActionSignature` signatures
  • `assignment_handler.go` — source validation + transitional inline conversion for `ListAssignedActionsForDevice`
  • `system_action_store.go` — system-action rebuild lookups
  • `user_selection_handler.go` — Action source enrichment
  • `control/inbox_worker.go` — 3 sites (dispatch, compliance, agent-scheduled)
  • `search/index.go` — action reindex sweep

Non-goals

  • ActionSet / Definition / Execution / Assignment — follow-ups.
  • Write-side projector queries — stay on `Queries()` per pattern.

Acceptance

  • Build / vet / staticcheck / gofmt: clean.
  • Tests pass: api (7m), control (9s).

Part of #242. Closes #271.

Summary by CodeRabbit

  • Refactor
    • Consolidated action data access across the app to a unified repository API for more consistent behavior and maintainability.
  • New Features
    • Added a core action domain model and a Postgres-backed action repository to support action listing, retrieval, name lookups, counting, and signature updates.
  • Chores
    • Removed legacy generated store import and aligned callers to the new repository layer.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 477c0d5d-08af-4952-be01-3bab05033887

📥 Commits

Reviewing files that changed from the base of the PR and between 3b45ba4 and 516411a.

📒 Files selected for processing (15)
  • internal/api/action_crud.go
  • internal/api/action_dispatch.go
  • internal/api/action_handler.go
  • internal/api/action_set_handler.go
  • internal/api/assignment_handler.go
  • internal/api/compliance_policy_handler.go
  • internal/api/device_handler.go
  • internal/api/system_action_store.go
  • internal/api/user_selection_handler.go
  • internal/control/inbox_worker.go
  • internal/search/index.go
  • internal/store/action.go
  • internal/store/postgres/action.go
  • internal/store/postgres/wire.go
  • internal/store/repos.go
🚧 Files skipped from review as they are similar to previous changes (14)
  • internal/api/assignment_handler.go
  • internal/api/action_handler.go
  • internal/api/user_selection_handler.go
  • internal/store/repos.go
  • internal/store/postgres/wire.go
  • internal/api/compliance_policy_handler.go
  • internal/control/inbox_worker.go
  • internal/api/system_action_store.go
  • internal/store/postgres/action.go
  • internal/api/device_handler.go
  • internal/api/action_dispatch.go
  • internal/store/action.go
  • internal/api/action_crud.go
  • internal/search/index.go

📝 Walkthrough

Walkthrough

This PR adds a store-level Action domain and ActionRepo, implements a Postgres ActionRepo, and migrates action access across API handlers, workers, and search from the query-layer (store.Queries()) to the repo-layer (store.Repos().Action.*).

Changes

Action Repository Foundation and Migration

Layer / File(s) Summary
Store foundation: action domain model and repository interface
internal/store/action.go
Introduces Action, ActionNamePair, ListActionsFilter, CountActionsFilter, UpdateActionSignatureParams, and the ActionRepo interface (Get, List, Count, NamesByIDs, UpdateSignature).
PostgreSQL ActionRepo implementation and wiring
internal/store/postgres/action.go, internal/store/repos.go, internal/store/postgres/wire.go
Implements ActionRepo using sqlc-generated queries, maps projection rows to store.Action, handles errors, and wires Action: NewAction(q) into NewRepos.
Action CRUD handlers and signature handling
internal/api/action_crud.go, internal/api/action_handler.go
Migrates Create/Get/List/Rename/Update handlers and persistActionSignature to use h.store.Repos().Action.*; updates actionToProto to accept store.Action and removes obsolete generated import usage.
Assignment handler and system action signing
internal/api/assignment_handler.go, internal/api/system_action_store.go
Migrates CreateAssignment action verification and assigned-action conversion to the repo model; SignActionByID now loads and persists signatures via ActionRepo.
Action dispatch and cross-domain lookups
internal/api/action_dispatch.go, internal/api/action_set_handler.go, internal/api/compliance_policy_handler.go, internal/api/device_handler.go, internal/api/user_selection_handler.go
Replaces query-layer action lookups and name-enrichment calls with repository-layer equivalents across dispatch, execution enrichment, sets, compliance rules, device flows, and user-selection enrichment.
Worker execution handling and search indexing
internal/control/inbox_worker.go, internal/search/index.go
Worker paths (execution creation, compliance checks, pending re-signing) and search index warming now use ActionRepo Get/List/Count/NamesByIDs APIs.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 A repo for actions hops into the light,
Old queries replaced, the code feels light,
From CRUD to workers, the calls now flow,
Postgres maps params where the signatures grow.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly identifies the main change: introducing ActionRepo as part of wave B.14 of the store refactoring, which directly matches the primary objective of the changeset.
Linked Issues check ✅ Passed The code changes fully implement the requirements from issue #271: ActionRepo interface with Get/List/Count/NamesByIDs/UpdateSignature methods, proper data boundaries (json.RawMessage for Params/ParamsCanonical/Schedule, []byte for Signature), and migration of ~20 call sites across API, control, and search packages.
Out of Scope Changes check ✅ Passed All changes are directly scoped to ActionRepo implementation and migration. No ActionSet, Definition, Execution, or Assignment implementations are included, correctly deferring these to follow-up PRs as specified in non-goals.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/271-action-repo

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/store/postgres/action.go`:
- Around line 70-77: The UpdateSignature implementation (function
UpdateSignature) currently calls the generated UpdateActionSignature query which
was annotated with :exec so it discards affected-row counts; update the SQL
annotation to :execrows in the generated query for UpdateActionSignature, then
change UpdateSignature to capture the returned affected row count from the
generated method and if it is zero return store.ErrNotFound; keep passing
generated.UpdateActionSignatureParams (ID, Signature, ParamsCanonical) but
handle the rows-return value and map zero rows to store.ErrNotFound.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 72b2b3d0-98c0-4395-9623-72a96a935ce9

📥 Commits

Reviewing files that changed from the base of the PR and between 8e6bf70 and 3b45ba4.

📒 Files selected for processing (15)
  • internal/api/action_crud.go
  • internal/api/action_dispatch.go
  • internal/api/action_handler.go
  • internal/api/action_set_handler.go
  • internal/api/assignment_handler.go
  • internal/api/compliance_policy_handler.go
  • internal/api/device_handler.go
  • internal/api/system_action_store.go
  • internal/api/user_selection_handler.go
  • internal/control/inbox_worker.go
  • internal/search/index.go
  • internal/store/action.go
  • internal/store/postgres/action.go
  • internal/store/postgres/wire.go
  • internal/store/repos.go

Comment on lines +70 to +77
func (a *Action) UpdateSignature(ctx context.Context, p store.UpdateActionSignatureParams) error {
if err := a.q.UpdateActionSignature(ctx, generated.UpdateActionSignatureParams{
ID: p.ID,
Signature: p.Signature,
ParamsCanonical: []byte(p.ParamsCanonical),
}); err != nil {
return fmt.Errorf("action: update signature: %w", err)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Find SQL declaration for UpdateActionSignature (look for :exec vs :execrows/:one):"
rg -n -C3 --glob '*.sql' '\bUpdateActionSignature\b'

echo
echo "2) Inspect generated method signature for UpdateActionSignature:"
rg -n -C3 --glob '*.go' 'func \(.*\) UpdateActionSignature\(' internal/store/generated

echo
echo "3) Inspect repository implementation call site:"
rg -n -C3 --glob '*.go' 'func \(a \*Action\) UpdateSignature\(' internal/store/postgres

Repository: manchtools/power-manage-server

Length of output: 1816


Add affected-row check to detect missing actions in signature updates.

The SQL query uses :exec, which discards the affected-row count. If the target ID does not exist, the update silently succeeds with zero rows modified. Change the SQL annotation from :exec to :execrows to detect this case and return store.ErrNotFound when no rows are updated.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/store/postgres/action.go` around lines 70 - 77, The UpdateSignature
implementation (function UpdateSignature) currently calls the generated
UpdateActionSignature query which was annotated with :exec so it discards
affected-row counts; update the SQL annotation to :execrows in the generated
query for UpdateActionSignature, then change UpdateSignature to capture the
returned affected row count from the generated method and if it is zero return
store.ErrNotFound; keep passing generated.UpdateActionSignatureParams (ID,
Signature, ParamsCanonical) but handle the rows-return value and map zero rows
to store.ErrNotFound.

ActionRepo is the foundation of the action-chain cluster:

  Get / List(filter) / Count(filter) / NamesByIDs / UpdateSignature

ListActionsFilter / CountActionsFilter pair ActionTypeFilter +
UnassignedOnly so paginated totals match. UpdateSignature is the
single non-event write the action domain owns — used by the CA
key-rotation pathway. Params / ParamsCanonical / Schedule stay as
json.RawMessage at the boundary per the JSONB normalize plan;
Signature stays as []byte (already opaque bytes at the wire).

Call sites migrated:
- action_crud.go + action_handler.go — full action CRUD path,
  actionToProto + persistActionSignature signatures shifted to
  store.Action / *store.Action
- assignment_handler.go — source validation for Action + transitional
  inline conversion for ListAssignedActionsForDevice row (the join
  type migrates with the Assignment domain)
- system_action_store.go — system-action rebuild lookups
- user_selection_handler.go — Action source enrichment in
  ListAvailableActions
- control/inbox_worker.go — execution dispatch, compliance trigger,
  agent-scheduled action lookups (3 sites)
- search/index.go — action reindex sweep

Non-goals:
- ActionSet / Definition / Execution / Assignment repos — each gets
  its own follow-up sub-wave. The chain is too big for one PR.
- Write-side projector queries — stay on Queries() per pattern.

Closes #271.
@PaulDotterer PaulDotterer force-pushed the feat/271-action-repo branch from 3b45ba4 to 516411a Compare May 15, 2026 22:29
@PaulDotterer PaulDotterer merged commit d53598e into main May 15, 2026
5 checks passed
@PaulDotterer PaulDotterer deleted the feat/271-action-repo branch May 15, 2026 22:46
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.

wave B.14: action repo (chain foundation)

1 participant