Documentation
¶
Index ¶
- Constants
- Variables
- func DescribeQueueState(j *Job, now time.Time) string
- type AdmitResult
- type AdmitStatus
- type BoltJobStore
- func (s *BoltJobStore) Admit(ctx context.Context, delivery Delivery, jobs []Job) (AdmitResult, error)
- func (s *BoltJobStore) ClaimNextJob(ctx context.Context, activePRs map[string]bool) (*Job, error)
- func (s *BoltJobStore) Close() error
- func (s *BoltJobStore) CommitPublicationOutcome(ctx context.Context, intent *OutputIntent, job *Job, prState *PRState) error
- func (s *BoltJobStore) CommitSupersededOutcome(ctx context.Context, intent *OutputIntent, job *Job, ...) error
- func (s *BoltJobStore) DB() *bbolt.DB
- func (s *BoltJobStore) DeferJob(ctx context.Context, jobID string, dueAt time.Time, reason string) (*Job, error)
- func (s *BoltJobStore) EarliestDeferredDue(ctx context.Context) (due time.Time, ok bool, err error)
- func (s *BoltJobStore) GetDashboardMetrics(ctx context.Context) (*DashboardMetrics, error)
- func (s *BoltJobStore) GetDelivery(ctx context.Context, key string) (*Delivery, error)
- func (s *BoltJobStore) GetHealthCounts(ctx context.Context, oldWaitWarning time.Duration) (HealthCounts, error)
- func (s *BoltJobStore) GetJob(ctx context.Context, id string) (*Job, error)
- func (s *BoltJobStore) GetOutputIntent(ctx context.Context, marker string) (*OutputIntent, error)
- func (s *BoltJobStore) GetPRState(ctx context.Context, key PRKey) (*PRState, error)
- func (s *BoltJobStore) InspectJobs(ctx context.Context) ([]*Job, error)
- func (s *BoltJobStore) ListPendingStatusIntents(ctx context.Context, limit int) ([]*OutputIntent, error)
- func (s *BoltJobStore) ListQueuedJobs(ctx context.Context) ([]*Job, error)
- func (s *BoltJobStore) MaintainTerminalRecords(ctx context.Context, now time.Time, limit int) (MaintenanceResult, error)
- func (s *BoltJobStore) RecoverInterruptedJobs(ctx context.Context) ([]*Job, error)
- func (s *BoltJobStore) RecoverJobs(ctx context.Context) ([]*Job, error)
- func (s *BoltJobStore) ReleasePR(ctx context.Context, prKey PRKey) error
- func (s *BoltJobStore) ResolveJob(ctx context.Context, jobID string, resolution string, ackDuplicateRisk bool) error
- func (s *BoltJobStore) SaveOutputIntent(ctx context.Context, intent *OutputIntent) error
- func (s *BoltJobStore) ScheduleSuccessorReview(ctx context.Context, prKey PRKey, owner, repo string, prNum int, ...) (*Job, error)
- func (s *BoltJobStore) UpdateJob(ctx context.Context, job *Job) error
- func (s *BoltJobStore) UpdateOutputIntent(ctx context.Context, intent *OutputIntent) error
- func (s *BoltJobStore) UpdatePRState(ctx context.Context, state *PRState) error
- type DashboardMetrics
- type DecisionLedger
- func (l *DecisionLedger) ClaimDecision(ctx context.Context, prKey PRKey, headSHA string, event string, jobID string) (bool, *DecisionRecord, error)
- func (l *DecisionLedger) GetDecision(ctx context.Context, prKey PRKey, headSHA string) (*DecisionRecord, error)
- func (l *DecisionLedger) MarkUncertain(ctx context.Context, prKey PRKey, headSHA string, reason string) error
- func (l *DecisionLedger) PruneTerminalDecisions(ctx context.Context, cutoff time.Time, limit int) (int, error)
- func (l *DecisionLedger) RecordPublished(ctx context.Context, prKey PRKey, headSHA string, reviewID int64) error
- type DecisionRecord
- type DecisionReviewClient
- type DecisionStatus
- type Delivery
- type HealthCounts
- type IntentVerdict
- type Job
- type JobExecutor
- type JobStore
- type JobSummary
- type LLMCaller
- type MaintenanceResult
- type NeedsAttentionRecorder
- type OutputIntent
- type PRKey
- type PRState
- type Publication
- type PublishDecisionResult
- type ReconcileResult
- type Scheduler
- func (s *Scheduler) LLMGate() llm.RequestGate
- func (s *Scheduler) SandboxGate() sandbox.AdmissionGate
- func (s *Scheduler) SetDeferPollInterval(d time.Duration)
- func (s *Scheduler) SetLLMGate(gate llm.RequestGate)
- func (s *Scheduler) SetSandboxGate(gate sandbox.AdmissionGate)
- func (s *Scheduler) Shutdown(ctx context.Context) error
- func (s *Scheduler) Start(ctx context.Context) error
- func (s *Scheduler) Stop()
- func (s *Scheduler) Wake()
- type Server
- func (s *Server) ListenAndServe() error
- func (s *Server) Routes() http.Handler
- func (s *Server) Scheduler() *Scheduler
- func (s *Server) SetEngine(engine *reviewer.Engine)
- func (s *Server) SetRuntimeError(err error)
- func (s *Server) SetScheduler(scheduler *Scheduler)
- func (s *Server) SetStore(store JobStore)
- func (s *Server) Shutdown(ctx context.Context) error
- func (s *Server) Start(ctx context.Context) error
- func (s *Server) Stop()
- func (s *Server) Store() JobStore
- type ServerJobExecutor
- type StatusOutbox
- type StoreOptions
Constants ¶
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) )
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).
const MaxDashboardRecentJobs = 50
MaxDashboardRecentJobs bounds the recent activity ledger returned by GetDashboardMetrics so dashboard polling stays O(50) after sorting.
const MaxEditHistoryEntries = 5
MaxEditHistoryEntries caps PRState.EditHistory; overflow drops oldest.
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 ¶
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") )
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") )
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 ¶
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 ¶
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 ¶
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 (*BoltJobStore) GetHealthCounts ¶
func (s *BoltJobStore) GetHealthCounts(ctx context.Context, oldWaitWarning time.Duration) (HealthCounts, error)
func (*BoltJobStore) GetOutputIntent ¶
func (s *BoltJobStore) GetOutputIntent(ctx context.Context, marker string) (*OutputIntent, error)
func (*BoltJobStore) GetPRState ¶
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 (*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.
type HealthCounts ¶
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 ¶
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 ¶
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.
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 ¶
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.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
func NewServerWithClients ¶
NewServerWithClients creates a Server with injected GitHub and LLM clients for testing.
func (*Server) ListenAndServe ¶
func (*Server) SetRuntimeError ¶
func (*Server) SetScheduler ¶
func (*Server) Shutdown ¶
Shutdown stops admission of new webhook events, drains workers within the provided context deadline, and closes the persistent database only after workers have stopped.
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.