storage

package
v0.51.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 8, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Index

Constants

View Source
const (
	JobTypeReview   = "review"   // Single commit review
	JobTypeRange    = "range"    // Commit range review
	JobTypeDirty    = "dirty"    // Uncommitted changes review
	JobTypeTask     = "task"     // Run/analyze/design/custom prompt
	JobTypeInsights = "insights" // Historical review insights analysis
	JobTypeCompact  = "compact"  // Consolidated review verification
	JobTypeFix      = "fix"      // Background fix using worktree
)

JobType classifies what kind of work a review job represents.

View Source
const (
	SyncStateMachineID        = "machine_id"
	SyncStateLastJobCursor    = "last_job_cursor"    // ID of last synced job
	SyncStateLastReviewCursor = "last_review_cursor" // Composite cursor for reviews (updated_at,id)
	SyncStateLastResponseID   = "last_response_id"   // ID of last synced response
	SyncStateSyncTargetID     = "sync_target_id"     // Database ID of last synced Postgres
)

Sync state keys

Variables

View Source
var ErrAmbiguousCommit = sql.ErrNoRows // Use sql.ErrNoRows for API compatibility; callers can check message

ErrAmbiguousCommit is returned when a SHA lookup matches multiple repos

View Source
var ErrRepoHasJobs = errors.New("repository has existing jobs; use cascade to delete them")

ErrRepoHasJobs is returned when trying to delete a repo with jobs without cascade

Functions

func DefaultDBPath

func DefaultDBPath() string

DefaultDBPath returns the default database path

func ExtractRepoNameFromIdentity added in v0.18.0

func ExtractRepoNameFromIdentity(identity string) string

ExtractRepoNameFromIdentity extracts a human-readable name from a git identity. Examples:

func GenerateUUID

func GenerateUUID() string

GenerateUUID generates a random UUID v4 string. Uses crypto/rand for secure random generation.

func ParseVerdict

func ParseVerdict(output string) string

ParseVerdict extracts P (pass) or F (fail) from review output. It intentionally uses a small set of deterministic signals: clear severity/findings markers mean fail, and clear pass phrases mean pass. We do not try to interpret narrative caveats after "No issues found." because that quickly turns into a brittle natural-language parser. If agent output is too chatty or mixes process narration with findings, that should be fixed in the review prompt rather than by adding more verdict heuristics here.

Types

type AgentStats added in v0.47.0

type AgentStats struct {
	Agent      string  `json:"agent"`
	Total      int     `json:"total"`
	Passed     int     `json:"passed"`
	Failed     int     `json:"failed"`
	Errors     int     `json:"errors"`
	PassRate   float64 `json:"pass_rate"`
	MedianSecs float64 `json:"median_duration_secs"`
}

AgentStats contains per-agent performance metrics. Total counts all jobs by this agent (including task and fix jobs). Passed and Failed count only verdict-bearing review jobs, so Passed + Failed may be less than Total. PassRate is Passed/(Passed+Failed).

type BatchPRRef added in v0.40.0

type BatchPRRef struct {
	GithubRepo string
	PRNumber   int
}

BatchPRRef identifies a (github_repo, pr_number) pair for batch lookups.

type BatchReviewResult added in v0.26.0

type BatchReviewResult struct {
	JobID      int64  `json:"job_id"`
	Agent      string `json:"agent"`
	ReviewType string `json:"review_type"`
	Output     string `json:"output"`
	Status     string `json:"status"` // "done" or "failed"
	Error      string `json:"error"`
}

BatchReviewResult holds the output of a single review job within a batch.

type BranchListResult added in v0.19.0

type BranchListResult struct {
	Branches       []BranchWithCount
	TotalCount     int
	NullsRemaining int // Number of jobs with NULL/empty branch (for backfill tracking)
}

BranchListResult contains branches with counts and metadata

type BranchWithCount added in v0.19.0

type BranchWithCount struct {
	Name  string `json:"name"`
	Count int    `json:"count"`
}

BranchWithCount represents a branch with its total job count

type CIPRBatch added in v0.26.0

type CIPRBatch struct {
	ID            int64  `json:"id"`
	GithubRepo    string `json:"github_repo"`
	PRNumber      int    `json:"pr_number"`
	HeadSHA       string `json:"head_sha"`
	TotalJobs     int    `json:"total_jobs"`
	CompletedJobs int    `json:"completed_jobs"`
	FailedJobs    int    `json:"failed_jobs"`
	Synthesized   bool   `json:"synthesized"`
}

CIPRBatch tracks a batch of CI review jobs for a single PR at a specific HEAD SHA. A batch contains multiple jobs (review_types x agents matrix).

type CIPRReview added in v0.26.0

type CIPRReview struct {
	ID         int64  `json:"id"`
	GithubRepo string `json:"github_repo"`
	PRNumber   int    `json:"pr_number"`
	HeadSHA    string `json:"head_sha"`
	JobID      int64  `json:"job_id"`
}

CIPRReview tracks which PRs have been reviewed at which HEAD SHA

type Commit

type Commit struct {
	ID        int64     `json:"id"`
	RepoID    int64     `json:"repo_id"`
	SHA       string    `json:"sha"`
	Author    string    `json:"author"`
	Subject   string    `json:"subject"`
	Timestamp time.Time `json:"timestamp"`
	CreatedAt time.Time `json:"created_at"`
}

type ComponentHealth

type ComponentHealth struct {
	Name    string `json:"name"`
	Healthy bool   `json:"healthy"`
	Message string `json:"message,omitempty"`
}

ComponentHealth represents the health of a single component

type DB

type DB struct {
	*sql.DB
}

func Open

func Open(dbPath string) (*DB, error)

Open opens or creates the database at the given path

func (*DB) AddComment added in v0.17.0

func (db *DB) AddComment(commitID int64, responder, response string) (*Response, error)

AddComment adds a comment to a commit (legacy - use AddCommentToJob for new code)

func (*DB) AddCommentToJob added in v0.17.0

func (db *DB) AddCommentToJob(jobID int64, responder, response string) (*Response, error)

AddCommentToJob adds a comment linked to a job/review

func (*DB) BackfillRepoIdentities

func (db *DB) BackfillRepoIdentities() (int, error)

BackfillRepoIdentities computes and sets identity for repos that don't have one. Uses config.ResolveRepoIdentity to ensure consistency with new repo creation. Returns the number of repos backfilled.

func (*DB) BackfillSourceMachineID

func (db *DB) BackfillSourceMachineID() error

BackfillSourceMachineID sets source_machine_id on existing rows that don't have one. This should be called when sync is first enabled.

func (*DB) BackfillVerdictBool added in v0.47.0

func (db *DB) BackfillVerdictBool() (int, error)

BackfillVerdictBool populates verdict_bool for reviews that have output but a NULL verdict_bool. Returns the number of rows updated.

func (*DB) CancelClosedPRBatches added in v0.40.0

func (db *DB) CancelClosedPRBatches(
	githubRepo string, prNumber int,
) ([]int64, error)

CancelClosedPRBatches cancels unclaimed pending batches (and their linked jobs) for a specific PR. Used when the PR is closed or merged. Skips batches that are currently claimed for synthesis to avoid racing with the posting flow. Returns the IDs of jobs that were canceled.

func (*DB) CancelJob

func (db *DB) CancelJob(jobID int64) error

CancelJob marks a running or queued job as canceled

func (*DB) CancelJobWithError added in v0.50.0

func (db *DB) CancelJobWithError(jobID int64, errMsg string) error

CancelJobWithError cancels a queued or running job and sets an error message explaining why it was canceled. Returns sql.ErrNoRows if the job is already terminal.

func (*DB) CancelSupersededBatches added in v0.26.0

func (db *DB) CancelSupersededBatches(githubRepo string, prNumber int, newHeadSHA string) ([]int64, error)

CancelSupersededBatches cancels jobs and removes batches for a PR that have been superseded by a new HEAD SHA. Only affects unsynthesized batches (where the comment hasn't been posted yet). Returns the IDs of jobs that were canceled.

func (*DB) ClaimBatchForSynthesis added in v0.26.0

func (db *DB) ClaimBatchForSynthesis(batchID int64) (bool, error)

ClaimBatchForSynthesis atomically marks a batch as claimed only if it hasn't been claimed yet (CAS). Sets claimed_at so stale claims can be detected and recovered. Returns true if this caller won the claim.

func (*DB) ClaimJob

func (db *DB) ClaimJob(workerID string) (*ReviewJob, error)

ClaimJob atomically claims the next queued job for a worker

func (*DB) ClearAllSyncedAt

func (db *DB) ClearAllSyncedAt() error

ClearAllSyncedAt clears all synced_at timestamps in the database. This is used when syncing to a new Postgres database to ensure all data gets re-synced.

func (*DB) CompleteFixJob added in v0.34.0

func (db *DB) CompleteFixJob(jobID int64, agent, prompt, output, patch string) error

CompleteFixJob atomically marks a fix job as done, stores the review, and persists the patch in a single transaction. This prevents invalid states where a patch is written but the job isn't done, or vice versa.

func (*DB) CompleteJob

func (db *DB) CompleteJob(jobID int64, agent, prompt, output string) error

CompleteJob marks a job as done and stores the review. Only updates if job is still in 'running' state (respects cancellation). If the job has an output_prefix, it will be prepended to the output.

func (*DB) CountBatchJobs added in v0.26.0

func (db *DB) CountBatchJobs(batchID int64) (int, error)

CountBatchJobs returns the number of jobs linked to a batch.

func (*DB) CountJobStats added in v0.28.0

func (db *DB) CountJobStats(repoFilter string, opts ...ListJobsOption) (JobStats, error)

CountJobStats returns aggregate done/closed/open counts using the same filter logic as ListJobs (repo, branch, closed).

func (*DB) CountStalledJobs

func (db *DB) CountStalledJobs(threshold time.Duration) (int, error)

CountStalledJobs returns the number of jobs that have been running longer than the threshold

func (*DB) CreateCIBatch added in v0.26.0

func (db *DB) CreateCIBatch(githubRepo string, prNumber int, headSHA string, totalJobs int) (*CIPRBatch, bool, error)

CreateCIBatch creates a new batch record for a PR. Uses INSERT OR IGNORE to handle races. Returns (batch, true) if this caller created the batch, or (batch, false) if the batch already existed (another poller won the race). Only the creator (created==true) should proceed to enqueue jobs.

func (*DB) DeleteCIBatch added in v0.26.0

func (db *DB) DeleteCIBatch(batchID int64) error

DeleteCIBatch removes a batch and its job links. Used to clean up after a partial enqueue failure so the next poll can retry.

func (*DB) DeleteEmptyBatches added in v0.26.0

func (db *DB) DeleteEmptyBatches() (int, error)

DeleteEmptyBatches removes batches with no linked jobs that are older than 1 minute. These are left behind when the daemon crashes between CreateCIBatch and RecordBatchJob. The age threshold avoids racing with in-progress enqueues.

func (*DB) DeleteRepo

func (db *DB) DeleteRepo(repoID int64, cascade bool) error

DeleteRepo deletes a repo and optionally its associated data If cascade is true, also deletes all jobs, reviews, and responses for the repo If cascade is false and jobs exist, returns ErrRepoHasJobs

func (*DB) EnqueueJob

func (db *DB) EnqueueJob(opts EnqueueOpts) (*ReviewJob, error)

EnqueueJob creates a new review job. The job type is inferred from opts.

func (*DB) FailJob

func (db *DB) FailJob(jobID int64, workerID string, errorMsg string) (bool, error)

FailJob marks a job as failed with an error message. Only updates if job is still in 'running' state and owned by the given worker (respects cancellation and prevents stale workers from failing reclaimed jobs). Pass empty workerID to skip the ownership check (for admin/test callers). Returns true if the job was actually updated (false when ownership or status check prevented the update).

func (*DB) FailoverJob added in v0.33.0

func (db *DB) FailoverJob(jobID int64, workerID, backupAgent, backupModel string) (bool, error)

FailoverJob atomically switches a running job to the given backup agent and requeues it. When backupModel is non-empty the job's model is set to that value; otherwise model is cleared (NULL) so the backup agent uses its CLI default. Returns false if the job is not in running state, the worker doesn't own the job, or the backup agent is the same as the current agent.

func (*DB) FinalizeBatch added in v0.26.0

func (db *DB) FinalizeBatch(batchID int64) error

FinalizeBatch clears claimed_at after a successful post. The batch stays synthesized=1 but with claimed_at=NULL, so GetStaleBatches won't re-pick it.

func (*DB) FindRepo

func (db *DB) FindRepo(identifier string) (*Repo, error)

FindRepo finds a repo by path or name (tries path first, then name)

func (*DB) FindReusableSessionCandidate added in v0.45.0

func (db *DB) FindReusableSessionCandidate(
	repoID int64, branch, agent, reviewType, worktreePath string,
) (*ReviewJob, error)

FindReusableSessionCandidate returns the newest reusable session candidate.

func (*DB) FindReusableSessionCandidates added in v0.45.0

func (db *DB) FindReusableSessionCandidates(
	repoID int64, branch, agent, reviewType, worktreePath string, limit int,
) ([]ReviewJob, error)

FindReusableSessionCandidates returns recent completed jobs with reusable sessions for the same repo, branch, agent, and review type, newest first.

func (*DB) GetAllCommentsForJob added in v0.51.0

func (db *DB) GetAllCommentsForJob(jobID, commitID int64, fallbackSHA string) ([]Response, error)

GetAllCommentsForJob returns all comments for a job, merging legacy commit-based comments via MergeResponses. When commitID > 0, fetches legacy comments by commit ID. Otherwise, if fallbackSHA is non-empty, fetches by SHA. Callers should validate the SHA (e.g. via git.LooksLikeSHA) before passing it here.

func (*DB) GetAllReviewsForGitRef added in v0.14.0

func (db *DB) GetAllReviewsForGitRef(gitRef string) ([]Review, error)

GetAllReviewsForGitRef returns all reviews for a git ref (commit SHA or range) for re-review context

func (*DB) GetBatchJobIDs added in v0.26.0

func (db *DB) GetBatchJobIDs(batchID int64) ([]int64, error)

GetBatchJobIDs returns the review job IDs linked to a batch.

func (*DB) GetBatchReviews added in v0.26.0

func (db *DB) GetBatchReviews(batchID int64) ([]BatchReviewResult, error)

GetBatchReviews returns all review results for a batch by joining through ci_pr_batch_jobs.

func (*DB) GetCIBatchByJobID added in v0.26.0

func (db *DB) GetCIBatchByJobID(jobID int64) (*CIPRBatch, error)

GetCIBatchByJobID looks up the batch that contains a given job ID via ci_pr_batch_jobs.

func (*DB) GetCIReviewByJobID added in v0.26.0

func (db *DB) GetCIReviewByJobID(jobID int64) (*CIPRReview, error)

GetCIReviewByJobID returns the CI PR review for a given job ID, if any

func (*DB) GetCommentsForCommit added in v0.17.0

func (db *DB) GetCommentsForCommit(commitID int64) ([]Response, error)

GetCommentsForCommit returns all comments for a commit

func (*DB) GetCommentsForCommitSHA added in v0.17.0

func (db *DB) GetCommentsForCommitSHA(sha string) ([]Response, error)

GetCommentsForCommitSHA returns all comments for a commit by SHA

func (*DB) GetCommentsForJob added in v0.17.0

func (db *DB) GetCommentsForJob(jobID int64) ([]Response, error)

GetCommentsForJob returns all comments linked to a job

func (*DB) GetCommentsToSync added in v0.17.0

func (db *DB) GetCommentsToSync(machineID string, limit int) ([]SyncableResponse, error)

GetCommentsToSync returns comments created locally that need to be pushed. Only returns comments whose parent job has already been synced.

func (*DB) GetCommitByID

func (db *DB) GetCommitByID(id int64) (*Commit, error)

GetCommitByID returns a commit by its ID

func (*DB) GetCommitByRepoAndSHA

func (db *DB) GetCommitByRepoAndSHA(repoID int64, sha string) (*Commit, error)

GetCommitByRepoAndSHA returns a commit by repo ID and SHA

func (*DB) GetCommitBySHA

func (db *DB) GetCommitBySHA(sha string) (*Commit, error)

GetCommitBySHA returns a commit by its SHA. DEPRECATED: This is a legacy API that doesn't handle the same SHA in different repos. Returns sql.ErrNoRows if no commit found, or if multiple repos have this SHA (ambiguous). Prefer using GetCommitByRepoAndSHA or job-based lookups instead.

func (*DB) GetExpiredBatches added in v0.50.0

func (db *DB) GetExpiredBatches(timeout time.Duration) ([]CIPRBatch, error)

GetExpiredBatches returns unsynthesized batches that have at least one done or failed job, at least one non-terminal job, and were created more than timeout ago. These batches should post early with available results. Only done/failed jobs qualify — user-canceled jobs are not meaningful results worth posting.

func (*DB) GetJobByID

func (db *DB) GetJobByID(id int64) (*ReviewJob, error)

func (*DB) GetJobCounts

func (db *DB) GetJobCounts() (queued, running, done, failed, canceled, applied, rebased int, err error)

GetJobCounts returns counts of jobs by status

func (*DB) GetJobRetryCount

func (db *DB) GetJobRetryCount(jobID int64) (int, error)

GetJobRetryCount returns the retry count for a job

func (*DB) GetJobsToSync

func (db *DB) GetJobsToSync(machineID string, limit int) ([]SyncableJob, error)

GetJobsToSync returns terminal jobs that need to be pushed to PostgreSQL. These are jobs created locally that haven't been synced or were updated since last sync.

func (*DB) GetJobsWithReviewsByIDs added in v0.33.0

func (db *DB) GetJobsWithReviewsByIDs(jobIDs []int64) (map[int64]JobWithReview, error)

GetJobsWithReviewsByIDs fetches jobs and their reviews in batch for the given job IDs. Returns a map of job ID to JobWithReview. Jobs without reviews are included with a nil Review.

func (*DB) GetKnownJobUUIDs

func (db *DB) GetKnownJobUUIDs() ([]string, error)

GetKnownJobUUIDs returns UUIDs of all jobs that have a UUID. Used to filter reviews when pulling from PostgreSQL.

func (*DB) GetMachineID

func (db *DB) GetMachineID() (string, error)

GetMachineID returns this machine's unique identifier, creating one if it doesn't exist. Uses INSERT OR IGNORE + SELECT to ensure concurrency-safe behavior. Treats empty values as missing and regenerates.

func (*DB) GetNonTerminalBatchJobIDs added in v0.50.0

func (db *DB) GetNonTerminalBatchJobIDs(batchID int64) ([]int64, error)

GetNonTerminalBatchJobIDs returns job IDs in a batch that are still queued or running (not done, failed, or canceled).

func (*DB) GetOrCreateCommit

func (db *DB) GetOrCreateCommit(repoID int64, sha, author, subject string, timestamp time.Time) (*Commit, error)

GetOrCreateCommit finds or creates a commit record. Lookups are by (repo_id, sha) to handle the same SHA in different repos.

func (*DB) GetOrCreateCommitByRepoAndSHA

func (db *DB) GetOrCreateCommitByRepoAndSHA(repoID int64, sha, author, subject string, timestamp time.Time) (int64, error)

GetOrCreateCommitByRepoAndSHA finds or creates a commit.

func (*DB) GetOrCreateRepo

func (db *DB) GetOrCreateRepo(rootPath string, identity ...string) (*Repo, error)

GetOrCreateRepo finds or creates a repo by its root path. If identity is provided, it will be stored; otherwise the identity field remains NULL.

func (*DB) GetOrCreateRepoByIdentity

func (db *DB) GetOrCreateRepoByIdentity(identity string) (int64, error)

GetOrCreateRepoByIdentity finds or creates a repo for syncing by identity. The logic is:

  1. If exactly one local repo has this identity, use it (always preferred)
  2. If a placeholder repo exists (root_path == identity), use it
  3. If 0 or 2+ local repos have this identity, create a placeholder

This ensures synced jobs attach to the right repo:

  • Single clone: jobs attach directly to the local repo
  • Multiple clones: jobs attach to a neutral placeholder
  • No local clone: placeholder serves as a sync-only repo

Note: Single local repos are always preferred, even if a placeholder exists from a previous sync (e.g., when there were 0 or 2+ clones before).

func (*DB) GetPendingBatchPRs added in v0.40.0

func (db *DB) GetPendingBatchPRs(
	githubRepo string,
) ([]BatchPRRef, error)

GetPendingBatchPRs returns the distinct (github_repo, pr_number) pairs that have unsynthesized, unclaimed batches. This lets the poller cross-reference pending batches against the open PR list without additional GitHub API calls.

func (*DB) GetRecentReviewsForRepo

func (db *DB) GetRecentReviewsForRepo(repoID int64, limit int) ([]Review, error)

GetRecentReviewsForRepo returns the N most recent reviews for a repo

func (*DB) GetRepoByID

func (db *DB) GetRepoByID(id int64) (*Repo, error)

GetRepoByID returns a repo by its ID

func (*DB) GetRepoByIdentity

func (db *DB) GetRepoByIdentity(identity string) (*Repo, error)

GetRepoByIdentity finds a repo by its identity. Returns nil if not found, error if duplicates exist.

func (*DB) GetRepoByIdentityCaseInsensitive added in v0.26.0

func (db *DB) GetRepoByIdentityCaseInsensitive(identity string) (*Repo, error)

GetRepoByIdentityCaseInsensitive is like GetRepoByIdentity but uses case-insensitive comparison. Used by the CI poller since GitHub owner/repo names are case-insensitive. Excludes sync placeholders (root_path == identity) which don't have a real local checkout.

func (*DB) GetRepoByName

func (db *DB) GetRepoByName(name string) (*Repo, error)

GetRepoByName returns a repo by its display name

func (*DB) GetRepoByPath

func (db *DB) GetRepoByPath(rootPath string) (*Repo, error)

GetRepoByPath returns a repo by its path

func (*DB) GetRepoStats

func (db *DB) GetRepoStats(repoID int64) (*RepoStats, error)

GetRepoStats returns detailed statistics for a repo

func (*DB) GetReviewByCommitSHA

func (db *DB) GetReviewByCommitSHA(sha string) (*Review, error)

GetReviewByCommitSHA finds the most recent review by commit SHA (searches git_ref field)

func (*DB) GetReviewByID

func (db *DB) GetReviewByID(reviewID int64) (*Review, error)

GetReviewByID finds a review by its ID

func (*DB) GetReviewByJobID

func (db *DB) GetReviewByJobID(jobID int64) (*Review, error)

GetReviewByJobID finds a review by its job ID

func (*DB) GetReviewsToSync

func (db *DB) GetReviewsToSync(machineID string, limit int) ([]SyncableReview, error)

GetReviewsToSync returns reviews modified locally that need to be pushed. Only returns reviews whose parent job has already been synced.

func (*DB) GetStaleBatches added in v0.26.0

func (db *DB) GetStaleBatches() ([]CIPRBatch, error)

GetStaleBatches returns batches that need synthesis attention. This covers:

  • Unclaimed batches where all jobs are terminal (dropped events, canceled jobs)
  • Stale claims where the daemon crashed mid-post (claimed_at > 5 minutes ago)

func (*DB) GetSummary added in v0.47.0

func (db *DB) GetSummary(opts SummaryOptions) (*Summary, error)

GetSummary computes aggregate review statistics. All sub-queries run inside a single read transaction for snapshot consistency.

func (*DB) GetSyncState

func (db *DB) GetSyncState(key string) (string, error)

GetSyncState retrieves a value from the sync_state table. Returns empty string if key doesn't exist.

func (*DB) HasCIBatch added in v0.26.0

func (db *DB) HasCIBatch(githubRepo string, prNumber int, headSHA string) (bool, error)

HasCIBatch checks if a batch already exists for this PR at this HEAD SHA. Only returns true if the batch has at least one linked job — an empty batch (from a crash between CreateCIBatch and RecordBatchJob) is treated as absent so the recovery path in processPR can clean it up.

func (*DB) HasCIReview added in v0.26.0

func (db *DB) HasCIReview(githubRepo string, prNumber int, headSHA string) (bool, error)

HasCIReview checks if a PR has already been reviewed at the given HEAD SHA

func (*DB) HasMeaningfulBatchResult added in v0.50.0

func (db *DB) HasMeaningfulBatchResult(batchID int64) (bool, error)

HasMeaningfulBatchResult reports whether a batch has at least one done or failed job (a result worth posting). User-canceled jobs without review output are excluded.

func (*DB) IncrementBatchCompleted added in v0.26.0

func (db *DB) IncrementBatchCompleted(batchID int64) (*CIPRBatch, error)

IncrementBatchCompleted atomically increments completed_jobs and returns the updated batch. The increment is conditional on synthesized=0 so late events arriving after the batch has been posted don't corrupt counters. Returns nil batch (no error) when the batch is already synthesized.

func (*DB) IncrementBatchFailed added in v0.26.0

func (db *DB) IncrementBatchFailed(batchID int64) (*CIPRBatch, error)

IncrementBatchFailed atomically increments failed_jobs and returns the updated batch. The increment is conditional on synthesized=0 so late events arriving after the batch has been posted don't corrupt counters. Returns nil batch (no error) when the batch is already synthesized.

func (*DB) IsBatchExpired added in v0.50.0

func (db *DB) IsBatchExpired(batchID int64, timeout time.Duration) (bool, error)

IsBatchExpired reports whether a batch was created more than timeout ago. Used to check if a partially-complete batch should post early.

func (*DB) IsBatchStale added in v0.26.0

func (db *DB) IsBatchStale(batchID int64) (bool, error)

IsBatchStale reports whether a batch has had no activity for more than 1 minute. Staleness is based on updated_at (bumped by each RecordBatchJob) rather than created_at, so legitimately slow creators are not reclaimed while they are still making progress.

func (*DB) LatestBatchTimeForPR added in v0.40.0

func (db *DB) LatestBatchTimeForPR(
	githubRepo string, prNumber int,
) (time.Time, error)

LatestBatchTimeForPR returns the created_at timestamp of the most recent batch for the given PR, regardless of HEAD SHA. Returns zero time if no batch exists.

func (*DB) ListBranchesWithCounts added in v0.19.0

func (db *DB) ListBranchesWithCounts(repoPaths []string) (*BranchListResult, error)

ListBranchesWithCounts returns all branches with their job counts If repoPaths is non-empty, filters to jobs in those repos only

func (*DB) ListJobs

func (db *DB) ListJobs(statusFilter string, repoFilter string, limit, offset int, opts ...ListJobsOption) ([]ReviewJob, error)

ListJobs returns jobs with optional status, repo, branch, and closed filters.

func (*DB) ListRepos

func (db *DB) ListRepos() ([]Repo, error)

ListRepos returns all repos in the database

func (*DB) ListReposWithReviewCounts

func (db *DB) ListReposWithReviewCounts(opts ...ListReposOption) ([]RepoWithCount, int, error)

ListReposWithReviewCounts returns repos with their total job counts. Options can filter by path prefix, branch, or both.

func (*DB) MarkCommentSynced added in v0.17.0

func (db *DB) MarkCommentSynced(responseID int64) error

MarkCommentSynced updates the synced_at timestamp for a comment

func (*DB) MarkCommentsSynced added in v0.17.0

func (db *DB) MarkCommentsSynced(responseIDs []int64) error

MarkCommentsSynced updates the synced_at timestamp for multiple comments

func (*DB) MarkJobApplied added in v0.34.0

func (db *DB) MarkJobApplied(jobID int64) error

MarkJobApplied transitions a fix job from done to applied.

func (*DB) MarkJobRebased added in v0.34.0

func (db *DB) MarkJobRebased(jobID int64) error

MarkJobRebased transitions a done fix job to the "rebased" terminal state. This indicates the patch was stale and a new rebase job was triggered.

func (*DB) MarkJobSynced

func (db *DB) MarkJobSynced(jobID int64) error

MarkJobSynced updates the synced_at timestamp for a job

func (*DB) MarkJobsSynced

func (db *DB) MarkJobsSynced(jobIDs []int64) error

MarkJobsSynced updates the synced_at timestamp for multiple jobs

func (*DB) MarkReviewClosed added in v0.40.0

func (db *DB) MarkReviewClosed(reviewID int64, closed bool) error

MarkReviewClosed marks a review as closed (or reopened) by review ID

func (*DB) MarkReviewClosedByJobID added in v0.40.0

func (db *DB) MarkReviewClosedByJobID(jobID int64, closed bool) error

MarkReviewClosedByJobID marks a review as closed (or reopened) by job ID

func (*DB) MarkReviewSynced

func (db *DB) MarkReviewSynced(reviewID int64) error

MarkReviewSynced updates the synced_at timestamp for a review

func (*DB) MarkReviewsSynced

func (db *DB) MarkReviewsSynced(reviewIDs []int64) error

MarkReviewsSynced updates the synced_at timestamp for multiple reviews

func (*DB) MergeRepos

func (db *DB) MergeRepos(sourceRepoID, targetRepoID int64) (int64, error)

MergeRepos moves all jobs and commits from sourceRepoID to targetRepoID, then deletes the source repo

func (*DB) ReconcileBatch added in v0.26.0

func (db *DB) ReconcileBatch(batchID int64) (*CIPRBatch, error)

ReconcileBatch corrects the completed/failed counts for a batch by counting actual job statuses from the database.

func (*DB) RecordBatchJob added in v0.26.0

func (db *DB) RecordBatchJob(batchID, jobID int64) error

RecordBatchJob links a review job to a batch and bumps the batch's updated_at timestamp as a heartbeat so staleness detection is based on inactivity rather than age from creation.

func (*DB) RecordCIReview added in v0.26.0

func (db *DB) RecordCIReview(githubRepo string, prNumber int, headSHA string, jobID int64) error

RecordCIReview records that a PR was reviewed at a given HEAD SHA

func (*DB) ReenqueueJob

func (db *DB) ReenqueueJob(jobID int64, opts ReenqueueOpts) error

ReenqueueJob resets a completed, failed, or canceled job back to queued status. This allows manual re-running of jobs to get a fresh review. For done jobs, the existing review is deleted to avoid unique constraint violations.

func (*DB) RemapJob added in v0.33.0

func (db *DB) RemapJob(
	repoID int64, oldSHA, newSHA, patchID string,
	author, subject string, timestamp time.Time,
) (int, error)

RemapJob atomically checks for matching jobs, creates the commit row, and updates git_ref — all in a single transaction to prevent orphan commit rows or races between concurrent remaps.

func (*DB) RemapJobGitRef added in v0.33.0

func (db *DB) RemapJobGitRef(
	repoID int64, oldSHA, newSHA, patchID string, newCommitID int64,
) (int, error)

RemapJobGitRef updates git_ref and commit_id for jobs matching oldSHA in a repo, used after rebases to preserve review history. If a job has a stored patch_id that differs from the provided one, that job is skipped (the commit's content changed). Returns the number of rows updated.

func (*DB) RenameRepo

func (db *DB) RenameRepo(identifier, newName string) (int64, error)

RenameRepo updates the display name of a repo identified by its path or current name

func (*DB) ResetStaleJobs

func (db *DB) ResetStaleJobs() error

ResetStaleJobs marks all running jobs as queued (for daemon restart)

func (*DB) RetryJob

func (db *DB) RetryJob(jobID int64, workerID string, maxRetries int) (bool, error)

RetryJob requeues a running job for retry if retry_count < maxRetries. When workerID is non-empty the update is scoped to the owning worker, preventing a stale/zombie worker from requeuing a reclaimed job. Pass empty workerID to skip the ownership check (for admin/test callers).

func (*DB) SaveJobCommandLine added in v0.51.0

func (db *DB) SaveJobCommandLine(jobID int64, cmdLine string) error

SaveJobCommandLine stores the actual agent command line used for this execution. Purely informational — reconstructed on each run.

func (*DB) SaveJobPatch added in v0.34.0

func (db *DB) SaveJobPatch(jobID int64, patch string) error

SaveJobPatch stores the generated patch for a completed fix job

func (*DB) SaveJobPrompt

func (db *DB) SaveJobPrompt(jobID int64, prompt string) error

SaveJobPrompt stores the prompt for a running job

func (*DB) SaveJobSessionID added in v0.44.0

func (db *DB) SaveJobSessionID(
	jobID int64, workerID, sessionID string,
) error

SaveJobSessionID stores the captured agent session ID for a job. The first captured ID wins so repeated lifecycle events do not overwrite it. The update is scoped to the current execution attempt: it requires status='running' and the given workerID so that a stale worker unwinding after cancel/retry cannot overwrite a session ID that belongs to a new attempt of the same job.

func (*DB) SaveJobTokenUsage added in v0.47.0

func (db *DB) SaveJobTokenUsage(jobID int64, tokenUsageJSON string) error

SaveJobTokenUsage stores a JSON blob of token consumption data.

func (*DB) SetRepoIdentity

func (db *DB) SetRepoIdentity(repoID int64, identity string) error

SetRepoIdentity sets the identity for a repo.

func (*DB) SetSyncState

func (db *DB) SetSyncState(key, value string) error

SetSyncState sets a value in the sync_state table (upsert).

func (*DB) UnclaimBatch added in v0.26.0

func (db *DB) UnclaimBatch(batchID int64) error

UnclaimBatch resets the synthesized flag so the reconciler can retry. Called when comment posting fails after a successful claim.

func (*DB) UpdateJobBranch added in v0.19.0

func (db *DB) UpdateJobBranch(jobID int64, branch string) (int64, error)

UpdateJobBranch sets the branch field for a job that doesn't have one. This is used to backfill the branch when it's derived from git. Only updates if the current branch is NULL or empty. Returns the number of rows affected (0 if branch was already set or job not found, 1 if updated).

func (*DB) UpsertPulledJob

func (db *DB) UpsertPulledJob(j PulledJob, repoID int64, commitID *int64) error

UpsertPulledJob inserts or updates a job from PostgreSQL into SQLite. Sets synced_at to prevent re-pushing. Requires repo to exist.

func (*DB) UpsertPulledResponse

func (db *DB) UpsertPulledResponse(r PulledResponse) error

UpsertPulledResponse inserts a response from PostgreSQL into SQLite.

func (*DB) UpsertPulledReview

func (db *DB) UpsertPulledReview(r PulledReview) error

UpsertPulledReview inserts or updates a review from PostgreSQL into SQLite.

type DaemonStatus

type DaemonStatus struct {
	Version             string `json:"version"`
	QueuedJobs          int    `json:"queued_jobs"`
	RunningJobs         int    `json:"running_jobs"`
	CompletedJobs       int    `json:"completed_jobs"`
	FailedJobs          int    `json:"failed_jobs"`
	CanceledJobs        int    `json:"canceled_jobs"`
	AppliedJobs         int    `json:"applied_jobs"`
	RebasedJobs         int    `json:"rebased_jobs"`
	ActiveWorkers       int    `json:"active_workers"`
	MaxWorkers          int    `json:"max_workers"`
	MachineID           string `json:"machine_id,omitempty"`            // Local machine ID for remote job detection
	ConfigReloadedAt    string `json:"config_reloaded_at,omitempty"`    // Last config reload timestamp (RFC3339Nano)
	ConfigReloadCounter uint64 `json:"config_reload_counter,omitempty"` // Monotonic reload counter (for sub-second detection)
}

type DurationStats added in v0.47.0

type DurationStats struct {
	ReviewP50 float64 `json:"review_p50_secs"`
	ReviewP90 float64 `json:"review_p90_secs"`
	ReviewP99 float64 `json:"review_p99_secs"`
	QueueP50  float64 `json:"queue_p50_secs"`
	QueueP90  float64 `json:"queue_p90_secs"`
	QueueP99  float64 `json:"queue_p99_secs"`
}

DurationStats contains duration percentiles in seconds.

type EnqueueOpts added in v0.26.0

type EnqueueOpts struct {
	RepoID            int64
	CommitID          int64  // >0 for single-commit reviews
	GitRef            string // SHA, "start..end" range, or "dirty"
	Branch            string
	SessionID         string
	Agent             string
	Model             string // Effective model for this run
	Provider          string // Effective provider for this run (e.g. "anthropic", "openai")
	RequestedModel    string // Explicitly requested model; empty means reevaluate on rerun
	RequestedProvider string // Explicitly requested provider; empty means reevaluate on rerun
	Reasoning         string
	ReviewType        string // e.g. "security" — changes which system prompt is used
	PatchID           string // Stable patch-id for rebase tracking
	DiffContent       string // For dirty reviews (captured at enqueue time)
	Prompt            string // For task jobs (pre-stored prompt)
	OutputPrefix      string // Prefix to prepend to review output
	Agentic           bool   // Allow file edits and command execution
	PromptPrebuilt    bool   // Prompt is prebuilt and should be used as-is by the worker
	Label             string // Display label in TUI for task jobs (default: "prompt")
	JobType           string // Explicit job type (review/range/dirty/task/compact/fix); inferred if empty
	ParentJobID       int64  // Parent job being fixed (for fix jobs)
	WorktreePath      string // Worktree checkout path (empty = use main repo root)
	MinSeverity       string // Minimum severity filter (canonical: critical/high/medium/low or empty)
}

EnqueueOpts contains options for creating any type of review job. The job type is inferred from which fields are set (in priority order):

  • Prompt != "" → "task" (custom prompt job)
  • DiffContent != "" → "dirty" (uncommitted changes)
  • CommitID > 0 → "review" (single commit)
  • otherwise → "range" (commit range)

type ErrorEntry

type ErrorEntry struct {
	Timestamp time.Time `json:"ts"`
	Level     string    `json:"level"`
	Component string    `json:"component"`
	Message   string    `json:"message"`
	JobID     int64     `json:"job_id,omitempty"`
}

ErrorEntry represents a single error log entry (mirrors daemon.ErrorEntry for API)

type FailureStats added in v0.47.0

type FailureStats struct {
	Total   int            `json:"total"`
	Retries int            `json:"retries"`
	Errors  map[string]int `json:"errors"`
}

FailureStats contains failure categorization.

type HealthStatus

type HealthStatus struct {
	Healthy      bool              `json:"healthy"`
	Uptime       string            `json:"uptime"`
	Version      string            `json:"version"`
	Components   []ComponentHealth `json:"components"`
	RecentErrors []ErrorEntry      `json:"recent_errors"`
	ErrorCount   int               `json:"error_count_24h"`
}

HealthStatus represents the overall daemon health

type JobStats added in v0.28.0

type JobStats struct {
	Done   int `json:"done"`
	Closed int `json:"closed"`
	Open   int `json:"open"`
}

GetJobByID returns a job by ID with joined fields JobStats holds aggregate counts for the queue status line.

type JobStatus

type JobStatus string
const (
	JobStatusQueued   JobStatus = "queued"
	JobStatusRunning  JobStatus = "running"
	JobStatusDone     JobStatus = "done"
	JobStatusFailed   JobStatus = "failed"
	JobStatusCanceled JobStatus = "canceled"
	JobStatusApplied  JobStatus = "applied"
	JobStatusRebased  JobStatus = "rebased"
)

type JobTypeStats added in v0.47.0

type JobTypeStats struct {
	Type    string `json:"type"`
	Count   int    `json:"count"`
	Applied int    `json:"applied,omitempty"`
	Rebased int    `json:"rebased,omitempty"`
}

JobTypeStats contains job counts by type with fix terminal status breakdown.

type JobWithPgIDs

type JobWithPgIDs struct {
	Job        SyncableJob
	PgRepoID   int64
	PgCommitID *int64
}

JobWithPgIDs represents a job with its resolved PostgreSQL repo and commit IDs

type JobWithReview added in v0.33.0

type JobWithReview struct {
	Job    ReviewJob `json:"job"`
	Review *Review   `json:"review,omitempty"`
}

JobWithReview pairs a job with its review for batch operations

type ListJobsOption added in v0.21.0

type ListJobsOption func(*listJobsOptions)

ListJobsOption configures optional filters for ListJobs.

func WithBeforeCursor added in v0.51.0

func WithBeforeCursor(id int64) ListJobsOption

WithBeforeCursor filters jobs to those with ID < cursor (for cursor pagination).

func WithBranch added in v0.21.0

func WithBranch(branch string) ListJobsOption

WithBranch filters jobs by exact branch name.

func WithBranchOrEmpty added in v0.21.1

func WithBranchOrEmpty(branch string) ListJobsOption

WithBranchOrEmpty filters jobs by branch name, also including jobs with no branch set (empty string or NULL).

func WithClosed added in v0.40.0

func WithClosed(closed bool) ListJobsOption

WithClosed filters jobs by closed state (true/false).

func WithExcludeJobType added in v0.34.0

func WithExcludeJobType(jobType string) ListJobsOption

WithExcludeJobType excludes jobs of the given type.

func WithGitRef added in v0.21.0

func WithGitRef(ref string) ListJobsOption

WithGitRef filters jobs by git ref.

func WithJobType added in v0.34.0

func WithJobType(jobType string) ListJobsOption

WithJobType filters jobs by job_type (e.g. "fix", "review").

func WithRepoPrefix added in v0.42.0

func WithRepoPrefix(prefix string) ListJobsOption

WithRepoPrefix filters jobs to repos whose root_path starts with the given prefix.

type ListReposOption added in v0.42.0

type ListReposOption func(*listReposOptions)

ListReposOption configures filtering for ListReposWithReviewCounts.

func WithRepoBranch added in v0.42.0

func WithRepoBranch(branch string) ListReposOption

WithRepoBranch filters repos to those having jobs on the given branch. Use "(none)" to filter for jobs without a branch.

func WithRepoPathPrefix added in v0.42.0

func WithRepoPathPrefix(prefix string) ListReposOption

WithRepoPathPrefix filters repos whose root_path starts with the given prefix.

type OverviewStats added in v0.47.0

type OverviewStats struct {
	Total    int `json:"total"`
	Queued   int `json:"queued"`
	Running  int `json:"running"`
	Done     int `json:"done"`
	Failed   int `json:"failed"`
	Canceled int `json:"canceled"`
	Applied  int `json:"applied"`
	Rebased  int `json:"rebased"`
}

OverviewStats contains job counts by status.

type PgPool

type PgPool struct {
	// contains filtered or unexported fields
}

PgPool wraps a pgx connection pool with reconnection logic

func NewPgPool

func NewPgPool(ctx context.Context, connString string, cfg PgPoolConfig) (*PgPool, error)

NewPgPool creates a new PostgreSQL connection pool. The connection string should be a PostgreSQL URL like: postgres://user:pass@host:port/dbname?sslmode=disable

func (*PgPool) BatchInsertResponses

func (p *PgPool) BatchInsertResponses(ctx context.Context, responses []SyncableResponse) ([]bool, error)

BatchInsertResponses inserts multiple responses in a single batch operation. Returns a boolean slice indicating success/failure for each item at the corresponding index.

func (*PgPool) BatchUpsertJobs

func (p *PgPool) BatchUpsertJobs(ctx context.Context, jobs []JobWithPgIDs) ([]bool, error)

BatchUpsertJobs inserts or updates multiple jobs in a single batch operation. The jobs must have their PgRepoID and PgCommitID already resolved. Returns a boolean slice indicating success/failure for each item at the corresponding index.

func (*PgPool) BatchUpsertReviews

func (p *PgPool) BatchUpsertReviews(ctx context.Context, reviews []SyncableReview) ([]bool, error)

BatchUpsertReviews inserts or updates multiple reviews in a single batch operation. Returns a boolean slice indicating success/failure for each item at the corresponding index.

func (*PgPool) Close

func (p *PgPool) Close()

Close closes the connection pool

func (*PgPool) EnsureSchema

func (p *PgPool) EnsureSchema(ctx context.Context) error

EnsureSchema creates the schema if it doesn't exist and checks version. If legacy tables exist in the public schema, they are migrated to roborev.

func (*PgPool) GetDatabaseID

func (p *PgPool) GetDatabaseID(ctx context.Context) (string, error)

GetDatabaseID returns the unique ID for this Postgres database. Creates one if it doesn't exist. This ID is used to detect when a client is syncing to a different database than before.

func (*PgPool) GetOrCreateCommit

func (p *PgPool) GetOrCreateCommit(ctx context.Context, repoID int64, sha, author, subject string, timestamp time.Time) (int64, error)

GetOrCreateCommit finds or creates a commit, returns the PostgreSQL ID

func (*PgPool) GetOrCreateRepo

func (p *PgPool) GetOrCreateRepo(ctx context.Context, identity string) (int64, error)

GetOrCreateRepo finds or creates a repo by identity, returns the PostgreSQL ID

func (*PgPool) InsertResponse

func (p *PgPool) InsertResponse(ctx context.Context, r SyncableResponse) error

InsertResponse inserts a response in PostgreSQL (append-only, no updates)

func (*PgPool) Ping

func (p *PgPool) Ping(ctx context.Context) error

Ping checks if the connection is alive

func (*PgPool) Pool

func (p *PgPool) Pool() *pgxpool.Pool

Pool returns the underlying pgxpool.Pool for direct access

func (*PgPool) PullJobs

func (p *PgPool) PullJobs(ctx context.Context, excludeMachineID string, cursor string, limit int) ([]PulledJob, string, error)

PullJobs fetches jobs from PostgreSQL updated after the given cursor. Cursor format: "updated_at id" (space-separated) or empty for first pull. Returns jobs not from the given machineID (to avoid echo).

func (*PgPool) PullResponses

func (p *PgPool) PullResponses(ctx context.Context, excludeMachineID string, afterID int64, limit int) ([]PulledResponse, int64, error)

PullResponses fetches responses from PostgreSQL created after the given ID cursor.

func (*PgPool) PullReviews

func (p *PgPool) PullReviews(ctx context.Context, excludeMachineID string, knownJobUUIDs []string, cursor string, limit int) ([]PulledReview, string, error)

PullReviews fetches reviews from PostgreSQL updated after the given cursor. Only fetches reviews for jobs in knownJobUUIDs to avoid cursor advancement past unknown jobs.

func (*PgPool) RegisterMachine

func (p *PgPool) RegisterMachine(ctx context.Context, machineID, name string) error

RegisterMachine registers or updates this machine in the machines table

func (*PgPool) Tx

func (p *PgPool) Tx(ctx context.Context, fn func(tx pgx.Tx) error) error

Tx runs a function within a transaction

func (*PgPool) UpsertJob

func (p *PgPool) UpsertJob(ctx context.Context, j SyncableJob, pgRepoID int64, pgCommitID *int64) error

UpsertJob inserts or updates a job in PostgreSQL

func (*PgPool) UpsertReview

func (p *PgPool) UpsertReview(ctx context.Context, r SyncableReview) error

UpsertReview inserts or updates a review in PostgreSQL

type PgPoolConfig

type PgPoolConfig struct {
	// ConnectTimeout is the timeout for initial connection (default: 5s)
	ConnectTimeout time.Duration
	// MaxConns is the maximum number of connections (default: 4)
	MaxConns int32
	// MinConns is the minimum number of connections (default: 0)
	MinConns int32
	// MaxConnLifetime is the maximum lifetime of a connection (default: 1h)
	MaxConnLifetime time.Duration
	// MaxConnIdleTime is the maximum idle time before closing (default: 30m)
	MaxConnIdleTime time.Duration
}

PgPoolConfig configures the PostgreSQL connection pool

func DefaultPgPoolConfig

func DefaultPgPoolConfig() PgPoolConfig

DefaultPgPoolConfig returns sensible defaults for the connection pool

type PulledJob

type PulledJob struct {
	UUID              string
	RepoIdentity      string
	CommitSHA         string
	CommitAuthor      string
	CommitSubject     string
	CommitTimestamp   time.Time
	GitRef            string
	SessionID         string
	Agent             string
	Model             string
	Provider          string
	RequestedModel    string
	RequestedProvider string
	Reasoning         string
	JobType           string
	ReviewType        string
	PatchID           string
	Status            string
	Agentic           bool
	EnqueuedAt        time.Time
	StartedAt         *time.Time
	FinishedAt        *time.Time
	Prompt            string
	DiffContent       *string
	Error             string
	TokenUsage        string
	WorktreePath      string
	MinSeverity       string
	SourceMachineID   string
	UpdatedAt         time.Time
}

PulledJob represents a job pulled from PostgreSQL

type PulledResponse

type PulledResponse struct {
	UUID            string
	JobUUID         string
	Responder       string
	Response        string
	SourceMachineID string
	CreatedAt       time.Time
}

PulledResponse represents a response pulled from PostgreSQL

type PulledReview

type PulledReview struct {
	UUID               string
	JobUUID            string
	Agent              string
	Prompt             string
	Output             string
	Closed             bool
	UpdatedByMachineID string
	CreatedAt          time.Time
	UpdatedAt          time.Time
}

PulledReview represents a review pulled from PostgreSQL

type ReenqueueOpts added in v0.50.0

type ReenqueueOpts struct {
	Model    string
	Provider string
}

type Repo

type Repo struct {
	ID        int64     `json:"id"`
	RootPath  string    `json:"root_path"`
	Name      string    `json:"name"`
	CreatedAt time.Time `json:"created_at"`
	Identity  string    `json:"identity,omitempty"` // Unique identity for sync (git remote URL, .roborev-id, or local path)
}

func PreferAutoClone added in v0.51.0

func PreferAutoClone(repos []Repo) *Repo

PreferAutoClone picks the best repo from multiple matches. It prefers auto-clones (root_path under {DataDir}/clones/) since CI manages those and they won't have dirty working tree state. If no auto-clone is found, it returns the most recently created repo. Sync placeholders (root_path == identity) are skipped defensively.

type RepoStats

type RepoStats struct {
	Repo          *Repo
	TotalJobs     int
	QueuedJobs    int
	RunningJobs   int
	CompletedJobs int
	FailedJobs    int
	PassedReviews int
	FailedReviews int
	ClosedReviews int
	OpenReviews   int
}

RepoStats contains statistics for a single repo

type RepoSummary added in v0.47.0

type RepoSummary struct {
	Name      string `json:"name"`
	Path      string `json:"path"`
	Total     int    `json:"total"`
	Passed    int    `json:"passed"`
	Failed    int    `json:"failed"`
	Addressed int    `json:"addressed"`
}

RepoSummary contains per-repo summary when querying across all repos.

type RepoWithCount

type RepoWithCount struct {
	Name     string `json:"name"`
	RootPath string `json:"root_path"`
	Count    int    `json:"count"`
}

RepoWithCount represents a repo with its total job count

type Response

type Response struct {
	ID        int64     `json:"id"`
	CommitID  *int64    `json:"commit_id,omitempty"` // For commit-based responses (legacy)
	JobID     *int64    `json:"job_id,omitempty"`    // For job/review-based responses
	Responder string    `json:"responder"`
	Response  string    `json:"response"`
	CreatedAt time.Time `json:"created_at"`

	// Sync fields
	UUID            string     `json:"uuid,omitempty"`              // Globally unique identifier for sync
	SourceMachineID string     `json:"source_machine_id,omitempty"` // Machine that created this response
	SyncedAt        *time.Time `json:"synced_at,omitempty"`         // Last sync time
}

func MergeResponses added in v0.51.0

func MergeResponses(primary, extra []Response) []Response

MergeResponses deduplicates two Response slices by ID and returns a chronologically sorted result. This is used wherever job-based and legacy commit-based comments are merged.

type Review

type Review struct {
	ID        int64     `json:"id"`
	JobID     int64     `json:"job_id"`
	Agent     string    `json:"agent"`
	Prompt    string    `json:"prompt"`
	Output    string    `json:"output"`
	CreatedAt time.Time `json:"created_at"`
	Closed    bool      `json:"closed"`

	// Sync fields
	UUID               string     `json:"uuid,omitempty"`                  // Globally unique identifier for sync
	UpdatedAt          *time.Time `json:"updated_at,omitempty"`            // Last modification time
	UpdatedByMachineID string     `json:"updated_by_machine_id,omitempty"` // Machine that last modified this review
	SyncedAt           *time.Time `json:"synced_at,omitempty"`             // Last sync time

	// Stored verdict: 1=pass, 0=fail, NULL=legacy (not yet backfilled)
	VerdictBool *int `json:"verdict_bool,omitempty"`

	// Joined fields
	Job *ReviewJob `json:"job,omitempty"`
}

type ReviewJob

type ReviewJob struct {
	ID                int64      `json:"id"`
	RepoID            int64      `json:"repo_id"`
	CommitID          *int64     `json:"commit_id,omitempty"`  // nil for ranges
	GitRef            string     `json:"git_ref"`              // SHA or "start..end" for ranges
	Branch            string     `json:"branch,omitempty"`     // Branch name at time of job creation
	SessionID         string     `json:"session_id,omitempty"` // Reused prior session or captured current session ID
	Agent             string     `json:"agent"`
	Model             string     `json:"model,omitempty"`              // Effective model for this run (for opencode: provider/model format)
	Provider          string     `json:"provider,omitempty"`           // Effective provider for this run (e.g., anthropic, openai)
	RequestedModel    string     `json:"requested_model,omitempty"`    // Explicitly requested model; empty means reevaluate on rerun
	RequestedProvider string     `json:"requested_provider,omitempty"` // Explicitly requested provider; empty means reevaluate on rerun
	Reasoning         string     `json:"reasoning,omitempty"`          // thorough, standard, fast (default: thorough)
	JobType           string     `json:"job_type"`                     // review, range, dirty, task, insights, compact, fix
	Status            JobStatus  `json:"status"`
	EnqueuedAt        time.Time  `json:"enqueued_at"`
	StartedAt         *time.Time `json:"started_at,omitempty"`
	FinishedAt        *time.Time `json:"finished_at,omitempty"`
	WorkerID          string     `json:"worker_id,omitempty"`
	Error             string     `json:"error,omitempty"`
	Prompt            string     `json:"prompt,omitempty"`
	RetryCount        int        `json:"retry_count"`
	DiffContent       *string    `json:"diff_content,omitempty"`  // For dirty reviews (uncommitted changes)
	Agentic           bool       `json:"agentic"`                 // Enable agentic mode (allow file edits)
	PromptPrebuilt    bool       `json:"prompt_prebuilt"`         // Prompt was set at enqueue time and should be used as-is
	ReviewType        string     `json:"review_type,omitempty"`   // Review type (e.g., "security") - changes system prompt
	PatchID           string     `json:"patch_id,omitempty"`      // Stable patch-id for rebase tracking
	OutputPrefix      string     `json:"output_prefix,omitempty"` // Prefix to prepend to review output
	ParentJobID       *int64     `json:"parent_job_id,omitempty"` // Job being fixed (for fix jobs)
	Patch             *string    `json:"patch,omitempty"`         // Generated diff patch (for completed fix jobs)
	WorktreePath      string     `json:"worktree_path,omitempty"` // Worktree checkout path (empty = use RepoPath)
	CommandLine       string     `json:"command_line,omitempty"`  // Actual agent command line used for this run
	MinSeverity       string     `json:"min_severity,omitempty"`
	TokenUsage        string     `json:"token_usage,omitempty"` // JSON blob from agentsview (token consumption)
	// Sync fields
	UUID            string     `json:"uuid,omitempty"`              // Globally unique identifier for sync
	SourceMachineID string     `json:"source_machine_id,omitempty"` // Machine that created this job
	UpdatedAt       *time.Time `json:"updated_at,omitempty"`        // Last modification time
	SyncedAt        *time.Time `json:"synced_at,omitempty"`         // Last sync time

	// Joined fields for convenience
	RepoPath      string  `json:"repo_path,omitempty"`
	RepoName      string  `json:"repo_name,omitempty"`
	CommitSubject string  `json:"commit_subject,omitempty"` // empty for ranges
	Closed        *bool   `json:"closed,omitempty"`         // nil if no review yet
	Verdict       *string `json:"verdict,omitempty"`        // P/F parsed from review output
}

func (ReviewJob) CommitIDValue added in v0.51.0

func (j ReviewJob) CommitIDValue() int64

CommitIDValue returns the commit ID as a plain int64 (0 if nil).

func (ReviewJob) HasViewableOutput added in v0.34.0

func (j ReviewJob) HasViewableOutput() bool

HasViewableOutput returns true if this job has completed and its review/patch can be viewed. This covers done, applied, and rebased terminal states.

func (ReviewJob) IsDirtyJob added in v0.26.0

func (j ReviewJob) IsDirtyJob() bool

IsDirtyJob returns true if this is a dirty review (uncommitted changes).

func (ReviewJob) IsFixJob added in v0.34.0

func (j ReviewJob) IsFixJob() bool

IsFixJob returns true if this is a background fix job.

func (ReviewJob) IsReviewJob added in v0.49.0

func (j ReviewJob) IsReviewJob() bool

IsReviewJob returns true if this is an actual code review (single commit, range, or dirty) rather than a task, insights, compact, or fix job. The legacy fallback uses positive review signals (CommitID, dirty ref, range ref) to avoid misclassifying old stored-prompt jobs that happen to have a GitRef.

func (ReviewJob) IsTaskJob added in v0.20.0

func (j ReviewJob) IsTaskJob() bool

IsTaskJob returns true if this is a task job (run, analyze, custom label) rather than a commit review or dirty review. Task jobs have pre-stored prompts and no verdicts. Compact jobs are not considered task jobs since they produce P/F verdicts.

func (ReviewJob) UsesStoredPrompt added in v0.34.0

func (j ReviewJob) UsesStoredPrompt() bool

UsesStoredPrompt returns true if this job type uses a pre-stored prompt (task, insights, compact, or fix). These job types have prompts built at enqueue time, not constructed by the worker from git data.

type Summary added in v0.47.0

type Summary struct {
	Since    time.Time      `json:"since"`
	RepoPath string         `json:"repo_path,omitempty"`
	Branch   string         `json:"branch,omitempty"`
	Overview OverviewStats  `json:"overview"`
	Verdicts VerdictStats   `json:"verdicts"`
	Agents   []AgentStats   `json:"agents"`
	Duration DurationStats  `json:"duration"`
	JobTypes []JobTypeStats `json:"job_types"`
	Failures FailureStats   `json:"failures"`
	Repos    []RepoSummary  `json:"repos,omitempty"`
}

Summary holds aggregate review statistics for a time window.

type SummaryOptions added in v0.47.0

type SummaryOptions struct {
	RepoPath string
	Branch   string
	Since    time.Time
	AllRepos bool
}

SummaryOptions configures the summary query.

type SyncProgress

type SyncProgress struct {
	Phase      string // "push" or "pull"
	BatchNum   int
	BatchJobs  int
	BatchRevs  int
	BatchResps int
	TotalJobs  int
	TotalRevs  int
	TotalResps int
}

SyncProgress reports progress during a sync operation

type SyncStats

type SyncStats struct {
	PushedJobs      int
	PushedReviews   int
	PushedResponses int
	PulledJobs      int
	PulledReviews   int
	PulledResponses int
}

SyncStats contains statistics from a sync operation

type SyncWorker

type SyncWorker struct {
	// contains filtered or unexported fields
}

SyncWorker handles background synchronization between SQLite and PostgreSQL

func NewSyncWorker

func NewSyncWorker(db *DB, cfg config.SyncConfig) *SyncWorker

NewSyncWorker creates a new sync worker

func (*SyncWorker) FinalPush

func (w *SyncWorker) FinalPush() error

FinalPush performs a push-only sync for graceful shutdown. This ensures all local changes are pushed before the daemon exits. Loops until all pending items are synced (not just one batch). Does not pull changes since we're shutting down.

func (*SyncWorker) HealthCheck

func (w *SyncWorker) HealthCheck() (healthy bool, message string)

HealthCheck returns the health status of the sync worker

func (*SyncWorker) SetSkipInitialSync added in v0.33.1

func (w *SyncWorker) SetSkipInitialSync(skip bool) error

SetSkipInitialSync disables the immediate doSync that normally runs right after connecting. Must be called before Start().

func (*SyncWorker) Start

func (w *SyncWorker) Start() error

Start begins the sync worker in a background goroutine. The worker can be stopped with Stop() and restarted with Start().

func (*SyncWorker) Stop

func (w *SyncWorker) Stop()

Stop gracefully stops the sync worker

func (*SyncWorker) SyncNow

func (w *SyncWorker) SyncNow() (*SyncStats, error)

SyncNow triggers an immediate sync cycle and returns statistics. Returns an error if the worker is not running or not connected. Loops until all pending items are pushed (not just one batch).

func (*SyncWorker) SyncNowWithProgress

func (w *SyncWorker) SyncNowWithProgress(progressFn func(SyncProgress) bool) (*SyncStats, error)

SyncNowWithProgress is like SyncNow but calls progressFn after each batch. If not connected, attempts to connect first.

type SyncableJob

type SyncableJob struct {
	ID                int64
	UUID              string
	RepoID            int64
	RepoIdentity      string
	CommitID          *int64
	CommitSHA         string
	CommitAuthor      string
	CommitSubject     string
	CommitTimestamp   time.Time
	GitRef            string
	SessionID         string
	Agent             string
	Model             string
	Provider          string
	RequestedModel    string
	RequestedProvider string
	Reasoning         string
	JobType           string
	ReviewType        string
	PatchID           string
	Status            string
	Agentic           bool
	EnqueuedAt        time.Time
	StartedAt         *time.Time
	FinishedAt        *time.Time
	Prompt            string
	DiffContent       *string
	Error             string
	TokenUsage        string
	WorktreePath      string
	MinSeverity       string
	SourceMachineID   string
	UpdatedAt         time.Time
}

SyncableJob contains job data needed for sync

type SyncableResponse

type SyncableResponse struct {
	ID              int64
	UUID            string
	JobID           int64
	JobUUID         string
	Responder       string
	Response        string
	SourceMachineID string
	CreatedAt       time.Time
}

SyncableResponse contains response data needed for sync

type SyncableReview

type SyncableReview struct {
	ID                 int64
	UUID               string
	JobID              int64
	JobUUID            string
	Agent              string
	Prompt             string
	Output             string
	Closed             bool
	UpdatedByMachineID string
	CreatedAt          time.Time
	UpdatedAt          time.Time
}

SyncableReview contains review data needed for sync

type VerdictStats added in v0.47.0

type VerdictStats struct {
	Total          int     `json:"total"`
	Passed         int     `json:"passed"`
	Failed         int     `json:"failed"`
	Addressed      int     `json:"addressed"`
	PassRate       float64 `json:"pass_rate"`
	ResolutionRate float64 `json:"resolution_rate"`
}

VerdictStats contains pass/fail/addressed counts for completed reviews.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL