server

package
v0.2.4 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2026 License: MIT Imports: 42 Imported by: 0

Documentation

Index

Constants

View Source
const (
	StoreSchemaVersion = 1

	MaxJobBytes        = 32 * 1024  // 32 KiB normalized job bound
	MaxReviewBodyBytes = 128 * 1024 // 128 KiB review output bound

	// EstimatedJobStorageReserve is the logical capacity reservation per job
	EstimatedJobStorageReserve = int64(MaxJobBytes + MaxReviewBodyBytes)
)
View Source
const IntentCommitThreshold = 0.70

IntentCommitThreshold is the minimum classifier confidence required for a commit verdict to be actionable. Verdicts below this threshold must resolve to a confirm comment, never to a push-capable job (D-21, D-36).

View Source
const MaxDashboardRecentJobs = 50

MaxDashboardRecentJobs bounds the recent activity ledger returned by GetDashboardMetrics so dashboard polling stays O(50) after sorting.

View Source
const MaxEditHistoryEntries = 5

MaxEditHistoryEntries caps PRState.EditHistory; overflow drops oldest.

View Source
const NetworkFetchStatusLine = "Network fetch: ON (trusted opt-in, agent tools only; PR code offline)"

NetworkFetchStatusLine marks jobs whose agent tools ran with trusted network opt-in. It names no packages, URLs, or contents — only the posture. Allowlist-first per D-04: the flag enables only the gateway-mediated fetch path consumed in plans 03/04, never open egress.

Variables

View Source
var (
	// ErrDuplicateDecision indicates a decision for this PR and head commit has already been claimed or published.
	ErrDuplicateDecision = errors.New("decision already claimed or published for head")
	// ErrDecisionNotFound indicates that no decision record exists for the given PR and head commit.
	ErrDecisionNotFound = errors.New("decision record not found")
	// ErrLedgerClosed indicates that the underlying ledger database is closed or uninitialized.
	ErrLedgerClosed = errors.New("decision ledger database is closed or nil")
)
View Source
var (
	ErrUnknownSchemaVersion = errors.New("unknown store schema version")
	ErrStoreClosed          = errors.New("job store is closed")
	ErrJobNotFound          = errors.New("job not found")
	ErrDeliveryNotFound     = errors.New("delivery not found")
	ErrPRNotFound           = errors.New("pr state not found")
	ErrIntentNotFound       = errors.New("output intent not found")
	ErrDatabaseLocked       = errors.New("database is locked by another process")
	ErrGenerationChanged    = errors.New("pr generation changed before publication outcome commit")
)
View Source
var ErrPublicationPersistence = errors.New("durable publication state unavailable")

ErrPublicationPersistence marks failures of the durable ledger (saving or committing intent/job/outcome state). Callers must treat these as non-success: accepted work is preserved and never reported completed.

Functions

func DescribeQueueState

func DescribeQueueState(j *Job, now time.Time) string

DescribeQueueState renders the operator-visible queue state of a job for inspection surfaces (--queue-inspect, health). Deferred attempts report their park state so operators can distinguish waiting work from stuck work; all other jobs report their ledger status unchanged.

Types

type AdmitResult

type AdmitResult struct {
	Status AdmitStatus
	Reason string
}

type AdmitStatus

type AdmitStatus int
const (
	AdmitAccepted AdmitStatus = iota
	AdmitDuplicate
	AdmitCollision
	AdmitCapacityFull
)

type BoltJobStore

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

func OpenJobStore

func OpenJobStore(path string, opts StoreOptions) (*BoltJobStore, error)

OpenJobStore opens or initializes a bbolt-backed JobStore at the specified path.

func (*BoltJobStore) Admit

func (s *BoltJobStore) Admit(ctx context.Context, delivery Delivery, jobs []Job) (AdmitResult, error)

Admit atomically checks delivery uniqueness and capacity, enqueues jobs, records receipt, and increments PR generation in a single transaction.

func (*BoltJobStore) ClaimNextJob

func (s *BoltJobStore) ClaimNextJob(ctx context.Context, activePRs map[string]bool) (*Job, error)

ClaimNextJob claims the oldest eligible queued job while respecting per-PR exclusion and reserving a successor slot when starting an automatic review.

func (*BoltJobStore) Close

func (s *BoltJobStore) Close() error

func (*BoltJobStore) CommitPublicationOutcome

func (s *BoltJobStore) CommitPublicationOutcome(ctx context.Context, intent *OutputIntent, job *Job, prState *PRState) error

CommitPublicationOutcome atomically commits a publication outcome: the saved intent, the job and — only for a confirmed current-head review publication — PRState.LastReviewedHead. It reads the current persisted job and PR generation inside the same transaction, rejects stale success after generation movement and preserves active/latest/pending-successor fields rather than overwriting them from a stale PRState copy.

func (*BoltJobStore) CommitSupersededOutcome

func (s *BoltJobStore) CommitSupersededOutcome(ctx context.Context, intent *OutputIntent, job *Job, successorBaseSHA, successorHeadSHA string) error

CommitSupersededOutcome commits a superseded outcome together with the durable latest-head successor obligation in one transaction, so a failed successor save can never leave a terminal job without a recoverable latest-head review.

func (*BoltJobStore) DB

func (s *BoltJobStore) DB() *bbolt.DB

DB returns the underlying bbolt.DB instance.

func (*BoltJobStore) DeferJob

func (s *BoltJobStore) DeferJob(ctx context.Context, jobID string, dueAt time.Time, reason string) (*Job, error)

DeferJob atomically parks a job as a deferred attempt due at dueAt. The job returns to queued with NotBeforeAt set, StartedAt cleared, and the reason recorded, so the worker is freed while the wait persists durably across restarts. Only queued, running, or uncertain jobs may be parked; repeating the same deferral is a no-op that returns the current state.

func (*BoltJobStore) EarliestDeferredDue

func (s *BoltJobStore) EarliestDeferredDue(ctx context.Context) (due time.Time, ok bool, err error)

EarliestDeferredDue reports the earliest future due time among queued deferred attempts. ok is false when no parked attempt is waiting.

func (*BoltJobStore) GetDashboardMetrics added in v0.2.4

func (s *BoltJobStore) GetDashboardMetrics(ctx context.Context) (*DashboardMetrics, error)

GetDashboardMetrics computes the read-only operations telemetry snapshot in one bbolt read transaction: a dashboard poll never takes a write lock and can never block an incoming webhook admission (T-14-04).

func (*BoltJobStore) GetDelivery

func (s *BoltJobStore) GetDelivery(ctx context.Context, key string) (*Delivery, error)

func (*BoltJobStore) GetHealthCounts

func (s *BoltJobStore) GetHealthCounts(ctx context.Context, oldWaitWarning time.Duration) (HealthCounts, error)

func (*BoltJobStore) GetJob

func (s *BoltJobStore) GetJob(ctx context.Context, id string) (*Job, error)

func (*BoltJobStore) GetOutputIntent

func (s *BoltJobStore) GetOutputIntent(ctx context.Context, marker string) (*OutputIntent, error)

func (*BoltJobStore) GetPRState

func (s *BoltJobStore) GetPRState(ctx context.Context, key PRKey) (*PRState, error)

func (*BoltJobStore) InspectJobs

func (s *BoltJobStore) InspectJobs(ctx context.Context) ([]*Job, error)

func (*BoltJobStore) ListPendingStatusIntents

func (s *BoltJobStore) ListPendingStatusIntents(ctx context.Context, limit int) ([]*OutputIntent, error)

ListPendingStatusIntents returns up to limit pending status output intents.

func (*BoltJobStore) ListQueuedJobs

func (s *BoltJobStore) ListQueuedJobs(ctx context.Context) ([]*Job, error)

func (*BoltJobStore) MaintainTerminalRecords

func (s *BoltJobStore) MaintainTerminalRecords(ctx context.Context, now time.Time, limit int) (MaintenanceResult, error)

MaintainTerminalRecords reclaims expired terminal job reservations and state, removes expired receipts, and pins any active, queued, or uncertain work.

func (*BoltJobStore) RecoverInterruptedJobs

func (s *BoltJobStore) RecoverInterruptedJobs(ctx context.Context) ([]*Job, error)

RecoverInterruptedJobs delegates to RecoverJobs for backward compatibility.

func (*BoltJobStore) RecoverJobs

func (s *BoltJobStore) RecoverJobs(ctx context.Context) ([]*Job, error)

RecoverJobs inspects uncompleted jobs on startup and sets their recovery phase: - Review with saved output intent: queued for ReconcileOutput without regeneration. - Interrupted review generation: requeued for generation. - Idempotent actions (labels): requeued for idempotent set-add. - Static actions (improve): requeued with owned intent. - Non-idempotent actions (describe, summary, docs, changelog, assistant, edit): marked needs_attention if unproven. - Uncertain and needs_attention jobs release worker slots while blocking subsequent PR actions.

func (*BoltJobStore) ReleasePR

func (s *BoltJobStore) ReleasePR(ctx context.Context, prKey PRKey) error

ReleasePR releases active execution for a PR, transferring or releasing successor reservations.

func (*BoltJobStore) ResolveJob

func (s *BoltJobStore) ResolveJob(ctx context.Context, jobID string, resolution string, ackDuplicateRisk bool) error

func (*BoltJobStore) SaveOutputIntent

func (s *BoltJobStore) SaveOutputIntent(ctx context.Context, intent *OutputIntent) error

func (*BoltJobStore) ScheduleSuccessorReview

func (s *BoltJobStore) ScheduleSuccessorReview(ctx context.Context, prKey PRKey, owner, repo string, prNum int, baseSHA, headSHA string) (*Job, error)

ScheduleSuccessorReview creates or updates a queued automatic review intent for the latest head, using the reserved successor capacity.

func (*BoltJobStore) UpdateJob

func (s *BoltJobStore) UpdateJob(ctx context.Context, job *Job) error

func (*BoltJobStore) UpdateOutputIntent

func (s *BoltJobStore) UpdateOutputIntent(ctx context.Context, intent *OutputIntent) error

func (*BoltJobStore) UpdatePRState

func (s *BoltJobStore) UpdatePRState(ctx context.Context, state *PRState) error

type DashboardMetrics added in v0.2.4

type DashboardMetrics struct {
	TotalPRs           int            `json:"total_prs"`
	TotalJobs          int            `json:"total_jobs"`
	ActiveWorkers      int            `json:"active_workers"`
	RunningJobs        int            `json:"running_jobs"`
	QueuedJobs         int            `json:"queued_jobs"`
	DeferredJobs       int            `json:"deferred_jobs"`
	NeedsAttentionJobs int            `json:"needs_attention_jobs"`
	AutonomousCommits  int            `json:"autonomous_commits"`
	Decisions          map[string]int `json:"decisions"`
	JobsByKind         map[string]int `json:"jobs_by_kind"`
	JobsByStatus       map[string]int `json:"jobs_by_status"`
	SuccessRate        float64        `json:"success_rate"`
	RecentJobs         []*JobSummary  `json:"recent_jobs"`
}

DashboardMetrics is the operational telemetry snapshot served at GET /api/v1/metrics and rendered by GET /dashboard. Every field is a counter or a sanitized job projection; no configuration secrets, webhook payloads, or GitHub/LLM credentials are included.

type DecisionLedger

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

DecisionLedger provides durable, atomic one-decision-per-head guarantees (D-04).

func NewDecisionLedger

func NewDecisionLedger(db *bbolt.DB) *DecisionLedger

NewDecisionLedger creates a DecisionLedger backed by bbolt.

func (*DecisionLedger) ClaimDecision

func (l *DecisionLedger) ClaimDecision(ctx context.Context, prKey PRKey, headSHA string, event string, jobID string) (bool, *DecisionRecord, error)

ClaimDecision reserves the decision for (PRKey, headSHA). Serialized per (PRKey, headSHA) mutex. If a record already exists, returns claimed=false, existing record, and nil. If no record exists, writes a new claimed record and returns claimed=true, new record, and nil (D-04).

func (*DecisionLedger) GetDecision

func (l *DecisionLedger) GetDecision(ctx context.Context, prKey PRKey, headSHA string) (*DecisionRecord, error)

GetDecision returns the recorded decision for (PRKey, headSHA), or nil if none exists.

func (*DecisionLedger) MarkUncertain

func (l *DecisionLedger) MarkUncertain(ctx context.Context, prKey PRKey, headSHA string, reason string) error

MarkUncertain records an ambiguous remote write error for operator resolution.

func (*DecisionLedger) PruneTerminalDecisions

func (l *DecisionLedger) PruneTerminalDecisions(ctx context.Context, cutoff time.Time, limit int) (int, error)

PruneTerminalDecisions removes expired published decisions older than cutoff. Part of terminal record maintenance; leaves claimed and uncertain decisions pinned.

func (*DecisionLedger) RecordPublished

func (l *DecisionLedger) RecordPublished(ctx context.Context, prKey PRKey, headSHA string, reviewID int64) error

RecordPublished marks a decision claim as successfully published with review ID.

type DecisionRecord

type DecisionRecord struct {
	PRKey       PRKey          `json:"pr_key"`
	HeadSHA     string         `json:"head_sha"`
	Event       string         `json:"event"`
	JobID       string         `json:"job_id"`
	ReviewID    int64          `json:"review_id,omitempty"`
	Status      DecisionStatus `json:"status"`
	ClaimedAt   time.Time      `json:"claimed_at"`
	PublishedAt *time.Time     `json:"published_at,omitempty"`
	Error       string         `json:"error,omitempty"`
}

DecisionRecord records durable decision state for a specific PR and head commit. Key format in bbolt: "<Host>/<RepoID>/<PRNumber>/<HeadSHA>".

type DecisionReviewClient

type DecisionReviewClient interface {
	PostDecisionReview(ctx context.Context, owner, repo string, number int, commitSHA string, event string, body string, suggestions []ghclient.InlineSuggestion) (*github.PullRequestReview, error)
}

DecisionReviewClient specifies the remote GitHub decision review write interface.

type DecisionStatus

type DecisionStatus string

DecisionStatus represents the lifecycle state of a decision claim.

const (
	// DecisionStatusClaimed indicates the decision has been reserved but remote publication is in progress.
	DecisionStatusClaimed DecisionStatus = "claimed"
	// DecisionStatusPublished indicates the decision was successfully created on GitHub.
	DecisionStatusPublished DecisionStatus = "published"
	// DecisionStatusUncertain indicates an ambiguous remote outcome occurred requiring operator resolution.
	DecisionStatusUncertain DecisionStatus = "uncertain"
)

type Delivery

type Delivery struct {
	Host        string    `json:"host"`
	RepoID      int64     `json:"repo_id"`
	DeliveryID  string    `json:"delivery_id"`
	EventKind   string    `json:"event_kind"`
	PayloadHash string    `json:"payload_hash"` // SHA-256 hex
	ReceivedAt  time.Time `json:"received_at"`
	JobIDs      []string  `json:"job_ids,omitempty"`
}

Delivery records an authenticated incoming webhook delivery receipt.

func (*Delivery) Key

func (d *Delivery) Key() string

type HealthCounts

type HealthCounts struct {
	Queued         int  `json:"queued"`
	Running        int  `json:"running"`
	Uncertain      int  `json:"uncertain"`
	NeedsAttention int  `json:"needs_attention"`
	Deferred       int  `json:"deferred"`
	OldWaitWarning bool `json:"old_wait_warning"`
}

type IntentVerdict

type IntentVerdict struct {
	Intent     string  `json:"intent"`
	Confidence float64 `json:"confidence"`
	Summary    string  `json:"summary"`
}

IntentVerdict is the classifier outcome for a freeform edit request. Intent is one of "commit", "question", or "unclear".

func ClassifyEditIntent

func ClassifyEditIntent(ctx context.Context, llmClient LLMCaller, commentBody string) (IntentVerdict, error)

ClassifyEditIntent asks the LLM whether commentBody requests a committed edit (commit), asks a question (question), or is undecidable (unclear). The summary value is a short English paraphrase of the request per D-35.

Callers must treat a commit verdict with Confidence below IntentCommitThreshold as a confirm comment, never as a push-capable job. On LLM error or unparseable output it returns an unclear verdict with zero confidence and a non-nil error so callers fail to confirm-comment, never to push.

type Job

type Job struct {
	ID              string     `json:"id"`
	Sequence        uint64     `json:"sequence"`
	Kind            string     `json:"kind"`    // "review", "labels", "describe", "summary", "docs", "changelog", "improve", "assistant", "edit"
	Trigger         string     `json:"trigger"` // "automatic", "explicit"
	Author          string     `json:"author"`
	CommentID       int64      `json:"comment_id,omitempty"`
	PRKey           PRKey      `json:"pr_key"`
	Owner           string     `json:"owner"`
	Repo            string     `json:"repo"`
	PRNumber        int        `json:"pr_number"`
	BaseSHA         string     `json:"base_sha"`
	HeadSHA         string     `json:"head_sha"`
	Generation      uint64     `json:"generation"`
	Status          string     `json:"status"` // "queued", "running", "completed", "failed", "superseded", "uncertain", "needs_attention"
	CreatedAt       time.Time  `json:"created_at"`
	StartedAt       *time.Time `json:"started_at,omitempty"`
	FinishedAt      *time.Time `json:"finished_at,omitempty"`
	RecoveryPhase   string     `json:"recovery_phase,omitempty"`
	Reservations    int64      `json:"reservations"`
	StatusCommentID int64      `json:"status_comment_id,omitempty"`
	OutputMarker    string     `json:"output_marker,omitempty"`
	// NotBeforeAt parks a deferred attempt in the durable queue until the due
	// time arrives. Zero value means immediately eligible; old rows unmarshal
	// unchanged and schema version stays 1.
	NotBeforeAt time.Time `json:"not_before_at,omitempty"`
	Payload     string    `json:"payload,omitempty"`
	// NetworkFetch opts this job's agent tools into the gateway-mediated
	// fetch path for this job only. False is the default (offline, D-02);
	// true is valid only for the job that carried an explicit trusted
	// opt-in (D-03) and resets to false at terminal state.
	NetworkFetch bool   `json:"network_fetch,omitempty"`
	Error        string `json:"error,omitempty"`
}

Job represents a unit of work admitted by the durable ledger.

type JobExecutor

type JobExecutor interface {
	ExecuteJob(ctx context.Context, job *Job) error
}

JobExecutor defines the execution contract for individual scheduled jobs.

type JobStore

type JobStore interface {
	Close() error
	Admit(ctx context.Context, delivery Delivery, jobs []Job) (AdmitResult, error)
	GetDelivery(ctx context.Context, key string) (*Delivery, error)
	GetJob(ctx context.Context, id string) (*Job, error)
	ListQueuedJobs(ctx context.Context) ([]*Job, error)
	UpdateJob(ctx context.Context, job *Job) error
	// GetDashboardMetrics computes the read-only operations telemetry snapshot
	// inside a single bbolt read transaction.
	GetDashboardMetrics(ctx context.Context) (*DashboardMetrics, error)
	GetPRState(ctx context.Context, key PRKey) (*PRState, error)
	UpdatePRState(ctx context.Context, state *PRState) error
	SaveOutputIntent(ctx context.Context, intent *OutputIntent) error
	GetOutputIntent(ctx context.Context, marker string) (*OutputIntent, error)
	UpdateOutputIntent(ctx context.Context, intent *OutputIntent) error
	// CommitPublicationOutcome atomically commits intent, job and (for confirmed
	// current-head review publication) PRState.LastReviewedHead in one transaction.
	CommitPublicationOutcome(ctx context.Context, intent *OutputIntent, job *Job, prState *PRState) error
	// CommitSupersededOutcome atomically commits a superseded outcome and the
	// latest-head successor obligation (when successor head is non-empty).
	CommitSupersededOutcome(ctx context.Context, intent *OutputIntent, job *Job, successorBaseSHA, successorHeadSHA string) error
	RecoverInterruptedJobs(ctx context.Context) ([]*Job, error)
	RecoverJobs(ctx context.Context) ([]*Job, error)
	InspectJobs(ctx context.Context) ([]*Job, error)
	ResolveJob(ctx context.Context, jobID string, resolution string, ackDuplicateRisk bool) error
	GetHealthCounts(ctx context.Context, oldWaitWarning time.Duration) (HealthCounts, error)
	ClaimNextJob(ctx context.Context, activePRs map[string]bool) (*Job, error)
	ReleasePR(ctx context.Context, prKey PRKey) error
	ScheduleSuccessorReview(ctx context.Context, prKey PRKey, owner, repo string, prNum int, baseSHA, headSHA string) (*Job, error)
	// DeferJob atomically parks a job as a deferred attempt due at dueAt: the
	// job returns to queued with NotBeforeAt set so workers are freed while
	// the wait persists durably. Repeating the same deferral is idempotent.
	DeferJob(ctx context.Context, jobID string, dueAt time.Time, reason string) (*Job, error)
	// EarliestDeferredDue reports the earliest future due time among queued
	// deferred attempts, so the scheduler can bound its idle poll.
	EarliestDeferredDue(ctx context.Context) (time.Time, bool, error)
	ListPendingStatusIntents(ctx context.Context, limit int) ([]*OutputIntent, error)
	MaintainTerminalRecords(ctx context.Context, now time.Time, limit int) (MaintenanceResult, error)
}

JobStore defines the storage boundary interface.

type JobSummary added in v0.2.4

type JobSummary struct {
	ID         string     `json:"id"`
	PRKey      string     `json:"pr_key"`
	Owner      string     `json:"owner"`
	Repo       string     `json:"repo"`
	PRNumber   int        `json:"pr_number"`
	Kind       string     `json:"kind"`
	Trigger    string     `json:"trigger"`
	Author     string     `json:"author"`
	Status     string     `json:"status"`
	HeadSHA    string     `json:"head_sha"`
	PRURL      string     `json:"pr_url"`
	CreatedAt  time.Time  `json:"created_at"`
	FinishedAt *time.Time `json:"finished_at,omitempty"`
	Error      string     `json:"error,omitempty"`
}

JobSummary is the sanitized, read-only projection of a Job used by the operations dashboard. It deliberately excludes Job.Payload, reservations, and every credential-bearing field: metrics surfaces must never leak secrets.

type LLMCaller

type LLMCaller interface {
	ChatCompletion(ctx context.Context, systemPrompt string, userMessage string) (string, error)
}

LLMCaller is the minimal completion surface ClassifyEditIntent needs. It matches the pkg/llm Client.ChatCompletion method shape so production code can pass *llm.Client directly while tests inject a fake.

type MaintenanceResult

type MaintenanceResult struct {
	Scanned  int `json:"scanned"`
	Deleted  int `json:"deleted"`
	Released int `json:"released"`
	Pinned   int `json:"pinned"`
}

MaintenanceResult contains counters for a bounded maintenance pass.

type NeedsAttentionRecorder

type NeedsAttentionRecorder func(ctx context.Context, job *Job, reason string)

NeedsAttentionRecorder specifies the hook to flag a job as needs_attention.

type OutputIntent

type OutputIntent struct {
	Marker        string `json:"marker"`
	JobID         string `json:"job_id"`
	Action        string `json:"action"`
	PRKey         PRKey  `json:"pr_key"`
	Owner         string `json:"owner"`
	Repo          string `json:"repo"`
	PRNumber      int    `json:"pr_number"`
	ExactHead     string `json:"exact_head"`
	BodyDigest    string `json:"body_digest"` // hex SHA-256
	Body          string `json:"body"`
	VerifiedActor string `json:"verified_actor"`
	Status        string `json:"status"` // "pending", "in_progress", "completed", "uncertain", "needs_attention"
	CommentID     int64  `json:"comment_id,omitempty"`
	// SupersededBody/SupersededDigest record the intended updated body of an owned
	// comment before it is edited as superseded, so restart can match either the
	// original or the updated owned content (additive, optional; schema stays v1).
	SupersededBody   string    `json:"superseded_body,omitempty"`
	SupersededDigest string    `json:"superseded_digest,omitempty"`
	CreatedAt        time.Time `json:"created_at"`
	UpdatedAt        time.Time `json:"updated_at"`
}

OutputIntent records intent before external GitHub mutations.

type PRKey

type PRKey struct {
	Host   string `json:"host"`
	RepoID int64  `json:"repo_id"`
	Number int    `json:"number"`
}

PRKey represents the unique identification for PR actions: canonical API host + base repository ID + PR number.

func MakePRKey

func MakePRKey(host string, repoID int64, number int) (PRKey, error)

func (PRKey) String

func (k PRKey) String() string

type PRState

type PRState struct {
	PRKey                PRKey  `json:"pr_key"`
	Owner                string `json:"owner"`
	Repo                 string `json:"repo"`
	Number               int    `json:"number"`
	Generation           uint64 `json:"generation"`
	LastReviewedHead     string `json:"last_reviewed_head,omitempty"`
	ActiveJobID          string `json:"active_job_id,omitempty"`
	HasReservedSuccessor bool   `json:"has_reserved_successor,omitempty"`
	PendingAutoJobID     string `json:"pending_auto_job_id,omitempty"`
	LatestHeadSHA        string `json:"latest_head_sha,omitempty"`
	HasBlockedAction     bool   `json:"has_blocked_action,omitempty"`
	BlockedReason        string `json:"blocked_reason,omitempty"`
	// LastBotCommitSHA records the commit OID created by the most recent
	// successful edit push on this PR, so the next edit job can surface the
	// prior bot diff as sticky context. Empty when no bot edit landed yet.
	LastBotCommitSHA string `json:"last_bot_commit_sha,omitempty"`
	// LastBotBaseSHA records the PR head the last bot edit applied to.
	LastBotBaseSHA string `json:"last_bot_base_sha,omitempty"`
	// EditHistory carries the most recent user edit instructions (oldest
	// first), capped at MaxEditHistoryEntries with oldest dropped on
	// overflow. Additive omitempty evolution; schema version stays 1.
	EditHistory []string `json:"edit_history,omitempty"`
}

PRState tracks PR-level generation and active execution.

type Publication

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

Publication handles safe, idempotent, durable status and review publication. It ensures that status comments are reused across transitions, review outputs are persisted before external writes, and ambiguous writes are safely reconciled without duplicating comments or repeating expensive LLM review generation.

func NewPublication

func NewPublication(store JobStore, gh *ghclient.Client) *Publication

NewPublication creates a new Publication reconciler.

func (*Publication) PublishStatus

func (p *Publication) PublishStatus(ctx context.Context, job *Job, statusText string) (int64, error)

PublishStatus updates or creates a service-owned status comment for a job. Every create/edit/replacement first commits a recoverable intent (body, stable marker, exact head, digest, owner identity); if that commit fails no remote write occurs. It patches existing owned status comments to prevent comment spam per transition, and only creates a replacement if a complete bounded scan proves absence.

func (*Publication) ReconcileOutput

func (p *Publication) ReconcileOutput(ctx context.Context, intent *OutputIntent) (*ReconcileResult, error)

ReconcileOutput reconciles a committed OutputIntent across every crash window. It never trusts the caller's in-memory intent alone: the saved record must exist, be readable and match. Any failed/nil/malformed final PR head, failed ownership proof or unavailable generation/ledger state yields an uncertain, nonterminal outcome that retains the original body, digest, marker and comment ID.

type PublishDecisionResult

type PublishDecisionResult struct {
	Duplicate bool
	Record    *DecisionRecord
	Review    *github.PullRequestReview
}

PublishDecisionResult captures the outcome of PublishDecision.

func PublishDecision

func PublishDecision(
	ctx context.Context,
	ledger *DecisionLedger,
	gh DecisionReviewClient,
	job *Job,
	event string,
	body string,
	suggestions []ghclient.InlineSuggestion,
	markNeedsAttention NeedsAttentionRecorder,
) (*PublishDecisionResult, error)

PublishDecision performs the atomic check-then-publish decision lifecycle: 1. Claims decision in ledger (D-04). If already claimed/published, returns duplicate without network calls. 2. On claimed, executes exactly ONE remote PostDecisionReview (D-15). 3. On success, records published with review ID. 4. On uncertain write error (timeout / 5xx on POST), marks uncertain in ledger and routes to needs_attention (D-16).

type ReconcileResult

type ReconcileResult struct {
	Status    string // "completed", "superseded", "uncertain", "needs_attention"
	CommentID int64
	Reused    bool
	Error     error
}

ReconcileResult describes the resolution of an OutputIntent reconciliation.

type Scheduler

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

Scheduler coordinates FIFO job execution with per-PR serialisation and fixed workers.

func NewScheduler

func NewScheduler(store JobStore, executor JobExecutor, workers int) *Scheduler

func (*Scheduler) LLMGate

func (s *Scheduler) LLMGate() llm.RequestGate

LLMGate returns the scheduler's shared LLM RequestGate.

func (*Scheduler) SandboxGate

func (s *Scheduler) SandboxGate() sandbox.AdmissionGate

SandboxGate returns the scheduler's shared sandbox AdmissionGate.

func (*Scheduler) SetDeferPollInterval

func (s *Scheduler) SetDeferPollInterval(d time.Duration)

SetDeferPollInterval overrides the bounded idle poll for due deferred attempts. Non-positive values keep the current setting.

func (*Scheduler) SetLLMGate

func (s *Scheduler) SetLLMGate(gate llm.RequestGate)

SetLLMGate assigns a shared LLM RequestGate to the scheduler.

func (*Scheduler) SetSandboxGate

func (s *Scheduler) SetSandboxGate(gate sandbox.AdmissionGate)

SetSandboxGate assigns a shared sandbox AdmissionGate to the scheduler.

func (*Scheduler) Shutdown

func (s *Scheduler) Shutdown(ctx context.Context) error

func (*Scheduler) Start

func (s *Scheduler) Start(ctx context.Context) error

func (*Scheduler) Stop

func (s *Scheduler) Stop()

func (*Scheduler) Wake

func (s *Scheduler) Wake()

type Server

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

func NewServer

func NewServer(cfg *config.Config) *Server

func NewServerWithClients

func NewServerWithClients(cfg *config.Config, gh *ghclient.Client, llmClient *llm.Client) *Server

NewServerWithClients creates a Server with injected GitHub and LLM clients for testing.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe() error

func (*Server) Routes

func (s *Server) Routes() http.Handler

func (*Server) Scheduler

func (s *Server) Scheduler() *Scheduler

func (*Server) SetEngine

func (s *Server) SetEngine(engine *reviewer.Engine)

func (*Server) SetRuntimeError

func (s *Server) SetRuntimeError(err error)

func (*Server) SetScheduler

func (s *Server) SetScheduler(scheduler *Scheduler)

func (*Server) SetStore

func (s *Server) SetStore(store JobStore)

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

Shutdown stops admission of new webhook events, drains workers within the provided context deadline, and closes the persistent database only after workers have stopped.

func (*Server) Start

func (s *Server) Start(ctx context.Context) error

Start opens durable state and starts workers. It creates no filesystem writes in setup mode. In normal mode, it opens the bbolt store and initiates the scheduler.

func (*Server) Stop

func (s *Server) Stop()

Stop stops workers and closes the durable job store.

func (*Server) Store

func (s *Server) Store() JobStore

type ServerJobExecutor

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

ServerJobExecutor executes jobs using server components and GitHub/LLM clients.

func NewServerJobExecutor

func NewServerJobExecutor(s *Server, store JobStore) *ServerJobExecutor

func (*ServerJobExecutor) ExecuteJob

func (e *ServerJobExecutor) ExecuteJob(ctx context.Context, job *Job) error

func (*ServerJobExecutor) SetDecisionLedger

func (e *ServerJobExecutor) SetDecisionLedger(l *DecisionLedger)

type StatusOutbox

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

StatusOutbox is a fixed, bounded background dispatcher that publishes queued status comments for admitted review jobs independently of business worker availability.

func NewStatusOutbox

func NewStatusOutbox(store JobStore, gh *ghclient.Client, pub *Publication) *StatusOutbox

NewStatusOutbox creates a new StatusOutbox.

func (*StatusOutbox) Start

func (o *StatusOutbox) Start(ctx context.Context)

Start begins the outbox dispatcher goroutine.

func (*StatusOutbox) Stop

func (o *StatusOutbox) Stop()

Stop terminates the dispatcher loop and waits for it to exit.

func (*StatusOutbox) Wake

func (o *StatusOutbox) Wake()

Wake signals the outbox to immediately check for pending status intents.

type StoreOptions

type StoreOptions struct {
	BacklogLimit  int
	DeliveryLimit int
	StateMaxBytes int64
	DeliveryTTL   time.Duration
	OpenTimeout   time.Duration
}

Jump to

Keyboard shortcuts

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