Feat v0.6.3 dead code sweep (#38)
All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-frontend (push) Successful in 6s
CI/CD / test-sqlite (push) Successful in 2m46s
CI/CD / test-go-pg (push) Successful in 2m47s
CI/CD / build-and-deploy (push) Successful in 26s

Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #38.
This commit is contained in:
2026-03-31 12:37:47 +00:00
committed by xcaliber
parent a887b4c78b
commit 3d4228f868
130 changed files with 522 additions and 1215 deletions

View File

@@ -42,19 +42,19 @@ type Stores struct {
ResourceGrants ResourceGrantStore
Notifications NotificationStore
NotifPrefs NotificationPreferenceStore
Presence PresenceStore // v0.29.0: User online/offline status
Health HealthStore // v0.29.0: Provider health window management
Connections ConnectionStore // v0.38.1: Extension connection credentials
Dependencies DependencyStore // v0.38.2: Library package dependency graph
Packages PackageStore // v0.28.7: Unified package registry (surfaces + extensions)
Workflows WorkflowStore // v0.26.1: Workflow definitions + stages
ExtPermissions ExtensionPermissionStore // v0.29.0: Extension declared/granted capabilities
ExtData ExtDataStore // v0.29.2: Extension namespaced table catalog
Tickets TicketStore // v0.32.0: WS auth tickets (PG-backed for cross-pod)
RateLimits RateLimitStore // v0.32.0: Distributed rate limiting
Triggers TriggerStore // v0.2.2: Extension event/webhook triggers
ScheduledTasks ScheduledTaskStore // v0.2.2: User-created cron tasks
Cluster ClusterStore // v0.6.0: PG-backed cluster node registry (nil on SQLite)
Presence PresenceStore
Health HealthStore
Connections ConnectionStore
Dependencies DependencyStore
Packages PackageStore
Workflows WorkflowStore
ExtPermissions ExtensionPermissionStore
ExtData ExtDataStore
Tickets TicketStore
RateLimits RateLimitStore
Triggers TriggerStore
ScheduledTasks ScheduledTaskStore
Cluster ClusterStore
}
// TeamAvailableModel is returned by CatalogStore.ListTeamAvailable.
@@ -85,7 +85,7 @@ type UserStore interface {
RevokeAllRefreshTokens(ctx context.Context, userID string) error
CleanExpiredTokens(ctx context.Context) error
// ── CS1 additions (v0.29.0) ──
// ── CS1 additions ──
// Exists returns true if a user with the given ID exists and is active.
Exists(ctx context.Context, userID string) (bool, error)
@@ -94,7 +94,7 @@ type UserStore interface {
// Excludes the calling user. Max 20 results.
SearchActive(ctx context.Context, excludeUserID, query string) ([]UserSearchResult, error)
// ── CS2 additions (v0.29.0) ──
// ── CS2 additions ──
// CountAll returns the total number of users.
CountAll(ctx context.Context) (int, error)
@@ -108,7 +108,7 @@ type UserStore interface {
// UpdateVaultKeys re-wraps the user's vault keys (password change).
UpdateVaultKeys(ctx context.Context, userID string, encUEK, salt, nonce []byte) error
// ── CS4 additions (v0.29.0) ──
// ── CS4 additions ──
// ClearVaultKeys nulls out vault columns and sets vault_set = false.
ClearVaultKeys(ctx context.Context, userID string) error
@@ -147,7 +147,7 @@ type TeamStore interface {
IsTeamAdmin(ctx context.Context, teamID, userID string) (bool, error)
IsMember(ctx context.Context, teamID, userID string) (bool, error)
// ── CS1 additions (v0.29.0) ──
// ── CS1 additions ──
// Exists returns true if a team with the given ID exists.
Exists(ctx context.Context, teamID string) (bool, error)
@@ -161,12 +161,12 @@ type TeamStore interface {
// ListTeamAuditActions returns distinct audit actions for a team's members.
ListTeamAuditActions(ctx context.Context, teamID string) ([]string, error)
// ── CS5b additions (v0.29.0) ──
// ── CS5b additions ──
// GetFirstTeamIDForUser returns the first team_id the user belongs to, or "" if none.
GetFirstTeamIDForUser(ctx context.Context, userID string) (string, error)
// ── CS6 additions (v0.29.0) ──
// ── CS6 additions ──
// AddMemberReturningID inserts a team member and returns the row ID.
AddMemberReturningID(ctx context.Context, teamID, userID, role string) (string, error)
@@ -175,11 +175,6 @@ type TeamStore interface {
MergeSettings(ctx context.Context, teamID, settingsJSON string) error
}
// ChannelListFilter holds filter options for ChannelStore.ListFiltered.
// ChannelListItem is returned by ListFiltered and GetForUser.
// ArchivedChannel is a view model for the admin archived channels list.
// MessageWithSender is returned by MessageStore.ListWithSenderInfo.
// ChannelSearchResult is returned by MessageStore.SearchInChannel.
// =========================================
// AUDIT STORE
// =========================================
@@ -212,7 +207,7 @@ type GlobalConfigStore interface {
Set(ctx context.Context, key string, value models.JSONMap, updatedBy string) error
GetAll(ctx context.Context) (map[string]models.JSONMap, error)
// ── OIDC state (v0.29.0-cs4) ──
// ── OIDC state ──
// SaveOIDCState stores a state+nonce pair for OIDC callback verification.
SaveOIDCState(ctx context.Context, state, nonce, redirectTo string) error
@@ -224,7 +219,7 @@ type GlobalConfigStore interface {
// CleanupOIDCState removes stale OIDC states older than 10 minutes.
CleanupOIDCState(ctx context.Context) error
// ── CS6 additions (v0.29.0) ──
// ── CS6 additions ──
// GetString returns the raw value column as a string for simple settings
// (e.g. bare JSON booleans like "true"/"false").
@@ -232,7 +227,7 @@ type GlobalConfigStore interface {
}
// =========================================
// GROUP STORE (v0.16.0)
// GROUP STORE
// =========================================
type GroupStore interface {
@@ -257,7 +252,7 @@ type GroupStore interface {
}
// =========================================
// RESOURCE GRANT STORE (v0.16.0)
// RESOURCE GRANT STORE
// =========================================
type ResourceGrantStore interface {
@@ -270,7 +265,7 @@ type ResourceGrantStore interface {
}
// =========================================
// NOTIFICATION STORE (v0.20.0)
// NOTIFICATION STORE
// =========================================
type NotificationStore interface {
@@ -284,7 +279,7 @@ type NotificationStore interface {
}
// =========================================
// NOTIFICATION PREFERENCES STORE (v0.20.0)
// NOTIFICATION PREFERENCES STORE
// =========================================
type NotificationPreferenceStore interface {
@@ -299,12 +294,12 @@ type NotificationPreferenceStore interface {
}
// =========================================
// SESSION STORE (v0.24.3)
// SESSION STORE
// =========================================
// =========================================
// HEALTH STORE (v0.29.0)
// HEALTH STORE
// =========================================
// HealthStore manages provider health windows. The full interface is used
@@ -315,7 +310,7 @@ type HealthStore interface {
}
// =========================================
// PRESENCE STORE (v0.29.0)
// PRESENCE STORE
// =========================================
// PresenceStore manages user online/offline status.
@@ -334,7 +329,7 @@ type PresenceStore interface {
// =========================================
// SHARED TYPES
// =========================================
// CONNECTION STORE (v0.38.1)
// CONNECTION STORE
// =========================================
type ConnectionStore interface {
@@ -367,7 +362,7 @@ type ConnectionStore interface {
}
// =========================================
// DEPENDENCY STORE (v0.38.2)
// DEPENDENCY STORE
// =========================================
type DependencyStore interface {

View File

@@ -6,7 +6,7 @@ import (
)
// PackageStore manages the unified package registry (surfaces + extensions).
// Replaces SurfaceRegistryStore and ExtensionStore (v0.28.7).
// Replaces SurfaceRegistryStore and ExtensionStore.
type PackageStore interface {
// ── Lifecycle (from SurfaceRegistryStore) ────────────
@@ -66,13 +66,13 @@ type PackageStore interface {
// DeleteUserSettings removes per-user settings, reverting to defaults.
DeleteUserSettings(ctx context.Context, pkgID, userID string) error
// ── Scoped visibility (v0.30.0) ────────────────
// ── Scoped visibility ────────────────
// ListVisiblePackages returns packages visible to the given user:
// global packages + team packages for user's teams + personal packages.
ListVisiblePackages(ctx context.Context, userID string) ([]PackageRegistration, error)
// ── Package lifecycle (v0.30.0) ─────────────────
// ── Package lifecycle ─────────────────
// SetSchemaVersion updates the current schema version for a package.
SetSchemaVersion(ctx context.Context, id string, version int) error
@@ -83,7 +83,7 @@ type PackageStore interface {
// SetPackageSettings stores admin-configured package-level settings.
SetPackageSettings(ctx context.Context, id string, settings json.RawMessage) error
// ── Team-level settings (v0.2.0) ─────────────────
// ── Team-level settings ─────────────────
// GetTeamSettings returns team-scoped overrides for a package.
GetTeamSettings(ctx context.Context, pkgID, teamID string) (json.RawMessage, error)
@@ -134,7 +134,7 @@ type PackageUserSettings struct {
IsEnabled bool `json:"is_enabled" db:"is_enabled"`
}
// PackageTeamSettings stores team-scoped overrides for a package (v0.2.0).
// PackageTeamSettings stores team-scoped overrides for a package.
type PackageTeamSettings struct {
PackageID string `json:"package_id" db:"package_id"`
TeamID string `json:"team_id" db:"team_id"`

View File

@@ -9,7 +9,7 @@ import (
"switchboard-core/models"
)
// ── ConnectionStore (v0.38.1) ────────────────────────
// ── ConnectionStore ────────────────────────
type ConnectionStore struct{}

View File

@@ -7,7 +7,7 @@ import (
"switchboard-core/models"
)
// ── DependencyStore (v0.38.2) ────────────────────────
// ── DependencyStore ────────────────────────
type DependencyStore struct{}

View File

@@ -58,7 +58,7 @@ func (s *GlobalConfigStore) GetAll(ctx context.Context) (map[string]models.JSONM
return result, rows.Err()
}
// ── OIDC state (v0.29.0-cs4) ────────────────────────────────────────────
// ── OIDC state ────────────────────────────────────────────
func (s *GlobalConfigStore) SaveOIDCState(ctx context.Context, state, nonce, redirectTo string) error {
_, err := DB.ExecContext(ctx, `
@@ -86,7 +86,7 @@ func (s *GlobalConfigStore) CleanupOIDCState(ctx context.Context) error {
return err
}
// ── CS6 additions (v0.29.0) ─────────────────────────────────────────────
// ── CS6 additions ─────────────────────────────────────────────
func (s *GlobalConfigStore) GetString(ctx context.Context, key string) (string, error) {
var val string

View File

@@ -310,7 +310,7 @@ func (s *PackageStore) scanMany(ctx context.Context, query string, args ...inter
return result, rows.Err()
}
// ── Scoped visibility (v0.30.0) ──────────────────
// ── Scoped visibility ──────────────────
func (s *PackageStore) ListVisiblePackages(ctx context.Context, userID string) ([]store.PackageRegistration, error) {
return s.scanMany(ctx, `
@@ -327,7 +327,7 @@ func (s *PackageStore) ListVisiblePackages(ctx context.Context, userID string) (
ORDER BY p.source, p.title`, userID)
}
// ── Package lifecycle (v0.30.0) ──────────────────
// ── Package lifecycle ──────────────────
func (s *PackageStore) SetSchemaVersion(ctx context.Context, id string, version int) error {
result, err := DB.ExecContext(ctx,
@@ -367,7 +367,7 @@ func (s *PackageStore) SetPackageSettings(ctx context.Context, id string, settin
return nil
}
// ── Team-level settings (v0.2.0) ─────────────────
// ── Team-level settings ─────────────────
func (s *PackageStore) GetTeamSettings(ctx context.Context, pkgID, teamID string) (json.RawMessage, error) {
var settings []byte

View File

@@ -7,7 +7,6 @@ import (
)
// RateLimitStore manages distributed rate limit counters in Postgres.
// v0.32.0: fixed-window counter — upsert per-second bucket, check burst.
type RateLimitStore struct{}
func NewRateLimitStore() *RateLimitStore { return &RateLimitStore{} }

View File

@@ -224,7 +224,7 @@ func (s *TeamStore) IsMember(ctx context.Context, teamID, userID string) (bool,
}
// ── CS1 additions (v0.29.0) ─────────────────────────────────────────────
// ── CS1 additions ─────────────────────────────────────────────
func (s *TeamStore) Exists(ctx context.Context, teamID string) (bool, error) {
var exists bool
@@ -279,7 +279,7 @@ func (s *TeamStore) ListTeamAuditActions(ctx context.Context, teamID string) ([]
return actions, rows.Err()
}
// ── CS5b additions (v0.29.0) ────────────────────────────────────────────
// ── CS5b additions ────────────────────────────────────────────
func (s *TeamStore) GetFirstTeamIDForUser(ctx context.Context, userID string) (string, error) {
var teamID string
@@ -291,7 +291,7 @@ func (s *TeamStore) GetFirstTeamIDForUser(ctx context.Context, userID string) (s
return teamID, nil
}
// ── CS6 additions (v0.29.0) ────────────────────────────────────────────
// ── CS6 additions ────────────────────────────────────────────
func (s *TeamStore) AddMemberReturningID(ctx context.Context, teamID, userID, role string) (string, error) {
var id string

View File

@@ -8,7 +8,6 @@ import (
)
// TicketStore manages WS auth tickets in Postgres.
// v0.32.0: replaces in-memory sync.Map for cross-pod validation.
type TicketStore struct{}
func NewTicketStore() *TicketStore { return &TicketStore{} }

View File

@@ -187,7 +187,7 @@ func scanOneUser(ctx context.Context, query string, args ...interface{}) (*model
ScanJSON(sj, &u.Settings)
return &u, nil
}
// ── CS1 additions (v0.29.0) ─────────────────────────────────────────────
// ── CS1 additions ─────────────────────────────────────────────
func (s *UserStore) Exists(ctx context.Context, userID string) (bool, error) {
var exists bool
@@ -231,7 +231,7 @@ func (s *UserStore) SearchActive(ctx context.Context, excludeUserID, query strin
return results, rows.Err()
}
// ── CS2 additions (v0.29.0) ─────────────────────────────────────────────
// ── CS2 additions ─────────────────────────────────────────────
func (s *UserStore) MergeSettings(ctx context.Context, userID string, patch []byte) error {
_, err := DB.ExecContext(ctx, `
@@ -268,7 +268,7 @@ func (s *UserStore) CountAll(ctx context.Context) (int, error) {
return count, err
}
// ── CS4 additions (v0.29.0) ─────────────────────────────────────────────
// ── CS4 additions ─────────────────────────────────────────────
func (s *UserStore) ClearVaultKeys(ctx context.Context, userID string) error {
_, err := DB.ExecContext(ctx, `

View File

@@ -404,7 +404,7 @@ func nullIfEmpty(s string) interface{} {
return s
}
// ── Instances (v0.3.1) ──────────────────────
// ── Instances ──────────────────────
func (s *WorkflowStore) CreateInstance(ctx context.Context, inst *models.WorkflowInstance) error {
stageData := jsonOrEmpty(inst.StageData)
@@ -573,7 +573,7 @@ func (s *WorkflowStore) ListActiveInstances(ctx context.Context) ([]models.Workf
return result, rows.Err()
}
// ── Assignments (v0.3.1) ────────────────────
// ── Assignments ────────────────────
func (s *WorkflowStore) CreateAssignment(ctx context.Context, a *models.WorkflowAssignment) error {
reviewData := jsonOrEmpty(a.ReviewData)
@@ -661,7 +661,7 @@ func (s *WorkflowStore) ListAssignmentsByUser(ctx context.Context, userID string
return s.queryAssignments(ctx, q, args...)
}
// ── Signoffs (v0.3.4) ─────────────────────────
// ── Signoffs ─────────────────────────
func (s *WorkflowStore) CreateSignoff(ctx context.Context, so *models.WorkflowSignoff) error {
return DB.QueryRowContext(ctx, `

View File

@@ -6,7 +6,6 @@ import (
)
// RateLimitStore manages distributed rate limit counters.
// v0.32.0: replaces in-memory token bucket for cross-pod rate limiting.
type RateLimitStore interface {
// Allow checks if a request is within the rate limit.
// key is "{scope}:{identifier}" e.g. "auth:192.168.1.1".

View File

@@ -1,6 +1,6 @@
package store
// settings_cascade.go — v0.2.0
// settings_cascade.go
//
// Pure functions for three-tier settings resolution:
// global (admin) → team → user

View File

@@ -11,7 +11,7 @@ import (
"switchboard-core/store"
)
// ── ConnectionStore (v0.38.1) ────────────────────────
// ── ConnectionStore ────────────────────────
type ConnectionStore struct{}

View File

@@ -7,7 +7,7 @@ import (
"switchboard-core/models"
)
// ── DependencyStore (v0.38.2) ────────────────────────
// ── DependencyStore ────────────────────────
type DependencyStore struct{}

View File

@@ -57,7 +57,7 @@ func (s *GlobalConfigStore) GetAll(ctx context.Context) (map[string]models.JSONM
return result, rows.Err()
}
// ── OIDC state (v0.29.0-cs4) ────────────────────────────────────────────
// ── OIDC state ────────────────────────────────────────────
func (s *GlobalConfigStore) SaveOIDCState(ctx context.Context, state, nonce, redirectTo string) error {
_, err := DB.ExecContext(ctx, `
@@ -84,7 +84,7 @@ func (s *GlobalConfigStore) CleanupOIDCState(ctx context.Context) error {
return err
}
// ── CS6 additions (v0.29.0) ─────────────────────────────────────────────
// ── CS6 additions ─────────────────────────────────────────────
func (s *GlobalConfigStore) GetString(ctx context.Context, key string) (string, error) {
var val string

View File

@@ -331,7 +331,7 @@ func (s *PackageStore) scanMany(ctx context.Context, query string, args ...inter
return result, rows.Err()
}
// ── Scoped visibility (v0.30.0) ──────────────────
// ── Scoped visibility ──────────────────
func (s *PackageStore) ListVisiblePackages(ctx context.Context, userID string) ([]store.PackageRegistration, error) {
return s.scanMany(ctx, `
@@ -348,7 +348,7 @@ func (s *PackageStore) ListVisiblePackages(ctx context.Context, userID string) (
ORDER BY p.source, p.title`, userID, userID)
}
// ── Package lifecycle (v0.30.0) ──────────────────
// ── Package lifecycle ──────────────────
func (s *PackageStore) SetSchemaVersion(ctx context.Context, id string, version int) error {
result, err := DB.ExecContext(ctx,
@@ -388,7 +388,7 @@ func (s *PackageStore) SetPackageSettings(ctx context.Context, id string, settin
return nil
}
// ── Team-level settings (v0.2.0) ─────────────────
// ── Team-level settings ─────────────────
func (s *PackageStore) GetTeamSettings(ctx context.Context, pkgID, teamID string) (json.RawMessage, error) {
var settings string

View File

@@ -7,7 +7,6 @@ import (
)
// RateLimitStore manages rate limit counters in SQLite.
// v0.32.0: functional parity for single-process test coverage.
type RateLimitStore struct{}
func NewRateLimitStore() *RateLimitStore { return &RateLimitStore{} }

View File

@@ -231,7 +231,7 @@ func (s *TeamStore) IsMember(ctx context.Context, teamID, userID string) (bool,
}
// ── CS1 additions (v0.29.0) ─────────────────────────────────────────────
// ── CS1 additions ─────────────────────────────────────────────
func (s *TeamStore) Exists(ctx context.Context, teamID string) (bool, error) {
var count int
@@ -286,7 +286,7 @@ func (s *TeamStore) ListTeamAuditActions(ctx context.Context, teamID string) ([]
return actions, rows.Err()
}
// ── CS5b additions (v0.29.0) ────────────────────────────────────────────
// ── CS5b additions ────────────────────────────────────────────
func (s *TeamStore) GetFirstTeamIDForUser(ctx context.Context, userID string) (string, error) {
var teamID string
@@ -298,7 +298,7 @@ func (s *TeamStore) GetFirstTeamIDForUser(ctx context.Context, userID string) (s
return teamID, nil
}
// ── CS6 additions (v0.29.0) ────────────────────────────────────────────
// ── CS6 additions ────────────────────────────────────────────
func (s *TeamStore) AddMemberReturningID(ctx context.Context, teamID, userID, role string) (string, error) {
id := store.NewID()

View File

@@ -8,7 +8,6 @@ import (
)
// TicketStore manages WS auth tickets in SQLite.
// v0.32.0: functional parity for single-process test coverage.
type TicketStore struct{}
func NewTicketStore() *TicketStore { return &TicketStore{} }

View File

@@ -194,7 +194,7 @@ func (s *UserStore) scanOne(ctx context.Context, query string, args ...interface
ScanJSON(sj, &u.Settings)
return &u, nil
}
// ── CS1 additions (v0.29.0) ─────────────────────────────────────────────
// ── CS1 additions ─────────────────────────────────────────────
func (s *UserStore) Exists(ctx context.Context, userID string) (bool, error) {
var count int
@@ -238,7 +238,7 @@ func (s *UserStore) SearchActive(ctx context.Context, excludeUserID, query strin
return results, rows.Err()
}
// ── CS2 additions (v0.29.0) ─────────────────────────────────────────────
// ── CS2 additions ─────────────────────────────────────────────
func (s *UserStore) MergeSettings(ctx context.Context, userID string, patch []byte) error {
_, err := DB.ExecContext(ctx, `
@@ -275,7 +275,7 @@ func (s *UserStore) CountAll(ctx context.Context) (int, error) {
return count, err
}
// ── CS4 additions (v0.29.0) ─────────────────────────────────────────────
// ── CS4 additions ─────────────────────────────────────────────
func (s *UserStore) ClearVaultKeys(ctx context.Context, userID string) error {
_, err := DB.ExecContext(ctx, `

View File

@@ -418,7 +418,7 @@ func nullIfEmpty(s string) interface{} {
return s
}
// ── Instances (v0.3.1) ──────────────────────
// ── Instances ──────────────────────
func (s *WorkflowStore) CreateInstance(ctx context.Context, inst *models.WorkflowInstance) error {
inst.ID = store.NewID()
@@ -597,7 +597,7 @@ func (s *WorkflowStore) ListActiveInstances(ctx context.Context) ([]models.Workf
return result, rows.Err()
}
// ── Assignments (v0.3.1) ────────────────────
// ── Assignments ────────────────────
func (s *WorkflowStore) CreateAssignment(ctx context.Context, a *models.WorkflowAssignment) error {
a.ID = store.NewID()
@@ -690,7 +690,7 @@ func (s *WorkflowStore) ListAssignmentsByUser(ctx context.Context, userID string
return s.queryAssignments(ctx, q, args...)
}
// ── Signoffs (v0.3.4) ─────────────────────────
// ── Signoffs ─────────────────────────
func (s *WorkflowStore) CreateSignoff(ctx context.Context, so *models.WorkflowSignoff) error {
so.ID = store.NewID()

View File

@@ -3,7 +3,6 @@ package store
import "context"
// TicketStore manages short-lived, single-use WebSocket auth tickets.
// v0.32.0: replaces in-memory sync.Map for cross-pod ticket validation.
type TicketStore interface {
// Issue creates a single-use ticket for the given user.
// Returns the opaque ticket ID (128-bit hex).

View File

@@ -31,7 +31,7 @@ type WorkflowStore interface {
GetVersion(ctx context.Context, workflowID string, versionNumber int) (*models.WorkflowVersion, error)
GetLatestVersion(ctx context.Context, workflowID string) (*models.WorkflowVersion, error)
// Instances (v0.3.1+)
// Instances
CreateInstance(ctx context.Context, inst *models.WorkflowInstance) error
GetInstance(ctx context.Context, id string) (*models.WorkflowInstance, error)
GetInstanceByToken(ctx context.Context, token string) (*models.WorkflowInstance, error)
@@ -43,7 +43,7 @@ type WorkflowStore interface {
MarkInstanceStale(ctx context.Context, id string) error
ListActiveInstances(ctx context.Context) ([]models.WorkflowInstance, error)
// Assignments (v0.3.1)
// Assignments
CreateAssignment(ctx context.Context, a *models.WorkflowAssignment) error
ClaimAssignment(ctx context.Context, id string, userID string) error
UnclaimAssignment(ctx context.Context, id string) error
@@ -53,7 +53,7 @@ type WorkflowStore interface {
ListAssignmentsByInstance(ctx context.Context, instanceID string) ([]models.WorkflowAssignment, error)
ListAssignmentsByUser(ctx context.Context, userID string, status string) ([]models.WorkflowAssignment, error)
// Signoffs (v0.3.4)
// Signoffs
CreateSignoff(ctx context.Context, s *models.WorkflowSignoff) error
ListSignoffs(ctx context.Context, instanceID, stage string) ([]models.WorkflowSignoff, error)
CountSignoffs(ctx context.Context, instanceID, stage, decision string) (int, error)