Documentation
¶
Index ¶
- func ItemKey(repo string, number int) string
- type CacheImpl
- func (c *CacheImpl) ApplyCommentAdded(key string, comment gh.Comment)
- func (c *CacheImpl) ApplyDelta(eventType string, payload []byte)
- func (c *CacheImpl) ApplyIssueClosed(key string)
- func (c *CacheImpl) ApplyLabelAdded(key, label string)
- func (c *CacheImpl) ApplyLabelRemoved(key, label string)
- func (c *CacheImpl) ApplyStatusBatch(updates map[string]string)
- func (c *CacheImpl) BootstrapFromProbe(items []gh.BoardProbeItem, projectID string)
- func (c *CacheImpl) FetchCheckRuns(owner, repo, sha string) ([]gh.CheckRun, error)
- func (c *CacheImpl) FetchCombinedStatus(owner, repo, ref string) ([]gh.CommitStatus, error)
- func (c *CacheImpl) FetchItemDetails(item *gh.ProjectItem) error
- func (c *CacheImpl) FetchLabels(owner, repo string, issueNumber int) ([]string, error)
- func (c *CacheImpl) FetchLinkedPR(owner, repo string, issueNumber int) (*gh.PRDetails, error)
- func (c *CacheImpl) FetchPRClosingIssues(owner, repo string, prNumber int) ([]int, error)
- func (c *CacheImpl) FetchPRMergeable(owner, repo string, prNumber int) (*bool, error)
- func (c *CacheImpl) FetchPRMergeableFields(owner, repo string, prNumber int) (*bool, string, error)
- func (c *CacheImpl) FetchPRMergeableState(owner, repo string, prNumber int) (string, error)
- func (c *CacheImpl) FetchPRMerged(owner, repo string, prNumber int) (bool, error)
- func (c *CacheImpl) FetchPRReviewDecision(owner, repo string, prNumber int) (string, error)
- func (c *CacheImpl) FetchPRReviewRequests(owner, repo string, prNumber int) ([]gh.ReviewRequest, error)
- func (c *CacheImpl) FetchPRReviews(owner, repo string, prNumber int) ([]gh.PRReview, error)
- func (c *CacheImpl) FetchPRsForSHA(owner, repo, sha string) ([]int, error)
- func (c *CacheImpl) FetchProjectBoard(owner, repo string, projectNum int, ownerType string) (*gh.ProjectBoard, error)
- func (c *CacheImpl) FetchProjectItem(owner, repo string, issueNumber int) (*gh.ProjectItem, error)
- func (c *CacheImpl) FetchStatusField(projectID string) (*gh.StatusField, error)
- func (c *CacheImpl) GetItemID(key string) (string, bool)
- func (c *CacheImpl) IsBootstrapped() bool
- func (c *CacheImpl) IsItemCacheFresh(repo string, number int, sourceUpdatedAt time.Time) bool
- func (c *CacheImpl) IsItemDeepFetched(repo string, number int) bool
- func (c *CacheImpl) IsPaused() bool
- func (c *CacheImpl) LightReconcile(owner, repo string, projectNum int, ownerType string) (driftCount int, driftedKeys []string, freshBoard *gh.ProjectBoard, err error)
- func (c *CacheImpl) Pause()
- func (c *CacheImpl) ProjectID() string
- func (c *CacheImpl) RateLimitStats() (rest, graphql gh.RateLimitStats)
- func (c *CacheImpl) Reconcile(board *gh.ProjectBoard)
- func (c *CacheImpl) RecordPRLinkage(fullRepo string, prNumber, issueNumber int)
- func (c *CacheImpl) RefreshCheckRunsLive(owner, repo, sha string) error
- func (c *CacheImpl) RegisterItemID(key, itemID string)
- func (c *CacheImpl) RemoveItem(itemID string)
- func (c *CacheImpl) Resume()
- func (c *CacheImpl) SetMatchEchoFn(fn func(eventType, action, key string))
- func (c *CacheImpl) Subscribe(o itemstate.Observer) func()
- func (c *CacheImpl) SubscribePause(fn func(bool)) func()
- func (c *CacheImpl) UpdateItemStatus(key, newStatus string)
- type GitHubAdapter
- func (a *GitHubAdapter) FetchCheckRuns(owner, repo, sha string) ([]gh.CheckRun, error)
- func (a *GitHubAdapter) FetchCombinedStatus(owner, repo, ref string) ([]gh.CommitStatus, error)
- func (a *GitHubAdapter) FetchItemDetails(item *gh.ProjectItem) error
- func (a *GitHubAdapter) FetchLabels(owner, repo string, issueNumber int) ([]string, error)
- func (a *GitHubAdapter) FetchLinkedPR(owner, repo string, issueNumber int) (*gh.PRDetails, error)
- func (a *GitHubAdapter) FetchPRClosingIssues(owner, repo string, prNumber int) ([]int, error)
- func (a *GitHubAdapter) FetchPRMergeable(owner, repo string, prNumber int) (*bool, error)
- func (a *GitHubAdapter) FetchPRMergeableFields(owner, repo string, prNumber int) (*bool, string, error)
- func (a *GitHubAdapter) FetchPRMergeableState(owner, repo string, prNumber int) (string, error)
- func (a *GitHubAdapter) FetchPRMerged(owner, repo string, prNumber int) (bool, error)
- func (a *GitHubAdapter) FetchPRReviewDecision(owner, repo string, prNumber int) (string, error)
- func (a *GitHubAdapter) FetchPRReviewRequests(owner, repo string, prNumber int) ([]gh.ReviewRequest, error)
- func (a *GitHubAdapter) FetchPRReviews(owner, repo string, prNumber int) ([]gh.PRReview, error)
- func (a *GitHubAdapter) FetchPRsForSHA(owner, repo, sha string) ([]int, error)
- func (a *GitHubAdapter) FetchProjectBoard(owner, repo string, projectNum int, ownerType string) (*gh.ProjectBoard, error)
- func (a *GitHubAdapter) FetchProjectItem(owner, repo string, issueNumber int) (*gh.ProjectItem, error)
- func (a *GitHubAdapter) FetchStatusField(projectID string) (*gh.StatusField, error)
- func (a *GitHubAdapter) RateLimitStats() (rest, graphql gh.RateLimitStats)
- type ReadClient
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type CacheImpl ¶
type CacheImpl struct {
// contains filtered or unexported fields
}
CacheImpl is a goroutine-safe in-memory board cache. Webhook delta functions write to it; the poll loop reads from it via the ReadClient interface. Falls back to a fallback ReadClient on cache miss.
Internal ownership split:
- store owns: items, shaToKey, itemIDToKey, prToKey, pendingCheckRuns
- CacheImpl owns: paused, recentMissCache, projectID/Title/OwnerType, localDeltaAt
Locking invariant: mu guards CacheImpl-local fields only. Store has its own internal mutex. NEVER hold mu while calling any Store method — this prevents deadlock if Store observers call back into CacheImpl.
func NewCacheImpl ¶
func NewCacheImpl(fallback ReadClient, store *itemstate.Store, logFn func(format string, args ...any)) *CacheImpl
NewCacheImpl creates an empty cache backed by fallback for misses. store must be the shared *itemstate.Store owned by the engine — passing nil panics.
func (*CacheImpl) ApplyCommentAdded ¶
ApplyCommentAdded appends comment to the cached comment list for the item identified by key. No-op when the key is not in the cache. Safe for concurrent use.
Note: LocalCommentAdded dedups by DatabaseID, mirroring IssueCommentCreated. If a webhook echo for the same comment arrives before the next Reconcile, the repeated LocalCommentAdded is a no-op rather than a duplicate append.
func (*CacheImpl) ApplyDelta ¶
ApplyDelta dispatches a webhook payload to the appropriate typed delta function. It is a no-op when the cache is paused (stream unhealthy).
func (*CacheImpl) ApplyIssueClosed ¶
ApplyIssueClosed marks the item identified by key as closed in the store. No-op when the key is not in the cache. Safe for concurrent use.
func (*CacheImpl) ApplyLabelAdded ¶
ApplyLabelAdded updates the cached label list for the item identified by key, appending label if not already present. No-op when the key is not in the cache. Safe for concurrent use.
func (*CacheImpl) ApplyLabelRemoved ¶
ApplyLabelRemoved updates the cached label list for the item identified by key, removing label if present. No-op when the key is not in the cache or label is absent. Safe for concurrent use.
func (*CacheImpl) ApplyStatusBatch ¶
ApplyStatusBatch updates Status for items identified by project-item node IDs. Entries whose itemID is not in the Store's itemIDToKey index are silently skipped. Safe for concurrent use.
func (*CacheImpl) BootstrapFromProbe ¶
func (c *CacheImpl) BootstrapFromProbe(items []gh.BoardProbeItem, projectID string)
BootstrapFromProbe populates the cache from a ProbeProjectBoard result instead of a full FetchProjectBoard. This is the preferred cold-start path: probe costs ~250 nodes vs ~2350 for a full shallow fetch on a 47-item board.
Labels are absent from probe results; startup scans that rely on label data (runStartupTransientLabelScan, runStartupTerminalScan) will see empty label sets and silently become no-ops after this bootstrap path. This is an accepted trade-off: stale transient labels on closed terminal items will not be detected at startup (very low probability; requires a crash mid-Done-stage). Active items are deep-fetched on the first probe cycle, populating their labels normally.
Sets LinkedPR.Number from each probe item's LinkedPRNumber so the subsequent probe cycle does not see spurious linkage-drift on items that already have a PR.
Must be called before any engine mutations flow through the shared store.
func (*CacheImpl) FetchCheckRuns ¶
FetchCheckRuns returns cached check runs for a SHA; falls back to GitHub on miss. Reads from Store.CheckRunsBySHA, which covers both pre-linkage (pendingCheckRuns) and post-linkage (LinkedPR.CheckRuns) runs. On total miss, fetches from GitHub and populates the Store via CheckRunCompleted mutations so subsequent calls are served from cache.
func (*CacheImpl) FetchCombinedStatus ¶ added in v0.0.76
func (c *CacheImpl) FetchCombinedStatus(owner, repo, ref string) ([]gh.CommitStatus, error)
FetchCombinedStatus always delegates to GitHub — classic commit statuses change without webhooks, same reasoning as FetchPRMergeableFields above.
func (*CacheImpl) FetchItemDetails ¶
func (c *CacheImpl) FetchItemDetails(item *gh.ProjectItem) error
FetchItemDetails copies cached deep fields into the passed item pointer. Deep fields: Body, URL, Author, Assignees, BlockedBy, Comments, LinkedPRNumber, LinkedPRHeadSHA, LinkedPRReviewRequests, LinkedPRReviews, LinkedPRReviewThreadComments, LinkedPRResolvedThreadCount.
Cache freshness contract: the cache is treated as authoritative only while the fresh board's pi.UpdatedAt has not advanced past LastSeenSourceUpdatedAt (the pi.UpdatedAt observed at the moment of the last successful deep fetch). When the board's updatedAt is newer, the cache is stale and we fall through to a real GraphQL fetch. pi.UpdatedAt is computed by FetchProjectBoard as max(issue.updatedAt, projectItem.updatedAt, linkedPR.updatedAt), so PR-side changes (new reviews, comments, draft toggles) bump it. Webhooks remain a pure optimization that mutate the cache between polls; in their absence (or when they're unhealthy), the board's updatedAt correctly forces a re-fetch.
Falls back to GitHub on cache miss or when the cache is stale, and populates the cache with the result.
func (*CacheImpl) FetchLabels ¶
FetchLabels returns the cached label list for an issue; falls back to GitHub on miss.
func (*CacheImpl) FetchLinkedPR ¶
FetchLinkedPR returns cached PR details for an issue; falls back to GitHub on miss or once the cached record exceeds linkedPRCacheTTL (#1303).
func (*CacheImpl) FetchPRClosingIssues ¶
FetchPRClosingIssues always delegates to GitHub — used by the auto-heal path in delta handlers.
func (*CacheImpl) FetchPRMergeable ¶
FetchPRMergeable always delegates to GitHub — mergeability changes without webhooks.
func (*CacheImpl) FetchPRMergeableFields ¶ added in v0.0.70
FetchPRMergeableFields always delegates to GitHub — mergeability changes without webhooks.
func (*CacheImpl) FetchPRMergeableState ¶
FetchPRMergeableState always delegates to GitHub — mergeability changes without webhooks.
func (*CacheImpl) FetchPRMerged ¶ added in v0.0.70
FetchPRMerged always delegates to GitHub — the authoritative merged flag must be fresh (the cache/list-endpoint copy lags right after a merge).
func (*CacheImpl) FetchPRReviewDecision ¶ added in v0.0.76
FetchPRReviewDecision always delegates to GitHub, no caching — same rationale as FetchPRReviews.
func (*CacheImpl) FetchPRReviewRequests ¶ added in v0.0.75
func (c *CacheImpl) FetchPRReviewRequests(owner, repo string, prNumber int) ([]gh.ReviewRequest, error)
FetchPRReviewRequests always delegates to GitHub, no caching — same rationale as FetchPRReviews.
func (*CacheImpl) FetchPRReviews ¶ added in v0.0.75
FetchPRReviews always delegates to GitHub, no caching — review state is highly time-sensitive and is only consulted while a base:<branch> item's review gate is actively open.
func (*CacheImpl) FetchPRsForSHA ¶
FetchPRsForSHA always delegates to GitHub — used by the auto-heal path in applyCheckRunCompleted.
func (*CacheImpl) FetchProjectBoard ¶
func (c *CacheImpl) FetchProjectBoard(owner, repo string, projectNum int, ownerType string) (*gh.ProjectBoard, error)
FetchProjectBoard returns a *gh.ProjectBoard reconstructed from the Store. Falls back to GitHub when the cache has not been bootstrapped or is paused.
func (*CacheImpl) FetchProjectItem ¶
FetchProjectItem always delegates to GitHub — used by ensureIssueInStore for the fallback fetch path.
func (*CacheImpl) FetchStatusField ¶
func (c *CacheImpl) FetchStatusField(projectID string) (*gh.StatusField, error)
FetchStatusField always delegates to GitHub — project metadata, not board-item state.
func (*CacheImpl) GetItemID ¶
GetItemID returns the project-item node ID (PVTI_...) for the given cache key. Returns ("", false) when the key is not present or has no ItemID.
func (*CacheImpl) IsBootstrapped ¶
IsBootstrapped returns true when the Store contains at least one cached item. Uses HasItems (O(1), non-allocating) rather than All to avoid a full snapshot allocation that would otherwise duplicate the one inside FetchProjectBoard. Called outside c.mu per the "NEVER hold mu while calling Store" invariant.
func (*CacheImpl) IsItemCacheFresh ¶
IsItemCacheFresh returns true when the cache has deep-fetched details for the given item AND those details are not stale relative to the supplied sourceUpdatedAt (typically pi.UpdatedAt from a fresh board read). When the cache is stale, FetchItemDetails will fall through to a GraphQL deep-fetch. Called outside c.mu.
func (*CacheImpl) IsItemDeepFetched ¶
IsItemDeepFetched returns true when the cache holds deep-fetched details for the given item (LastDeepFetchAt is non-zero). Called outside c.mu.
Note: this only reports whether a deep fetch ever happened; it does not check freshness. Callers that need to know whether the cache is currently authoritative should use IsItemCacheFresh.
func (*CacheImpl) LightReconcile ¶
func (c *CacheImpl) LightReconcile(owner, repo string, projectNum int, ownerType string) (driftCount int, driftedKeys []string, freshBoard *gh.ProjectBoard, err error)
LightReconcile fetches a fresh shallow board snapshot from GitHub and compares it against the current cache state on two fields: status and updatedAt. Label count is intentionally excluded: the board query returns at most 30 labels (shallow), while the cache may hold the full deep-fetched set; comparing counts would produce persistent false-positive drift for issues with >30 labels. Label mutations are captured by updatedAt, so the two-field check is sufficient.
Note: LightReconcile still calls FetchProjectBoard (full shallow with labels). The per-poll probe path (engine/poll.go runProbeAndDeepFetch) is the primary cost-reduction mechanism; LightReconcile fires at most 20×/hour in webhook mode only, making it a lower-priority optimization target.
Returns the number of drifted items, their keys, and the fresh board (to avoid a double-fetch when the caller passes it to Reconcile on drift).
On network error the method returns a non-nil err, nil freshBoard, and 0 drift. The caller should log a warning and make no health state change.
LightReconcile must not hold c.mu during the FetchProjectBoard call, following the "NEVER hold mu while calling Store" invariant and avoiding slow I/O under lock.
func (*CacheImpl) Pause ¶
func (c *CacheImpl) Pause()
Pause stops delta application (called on WebhookStreamUnhealthy transition). Observers are called after the lock is released, and only on an actual false→true transition to avoid spamming observers on repeated Pause calls.
func (*CacheImpl) ProjectID ¶
ProjectID returns the project node ID stored from the last Bootstrap/Reconcile call. Returns "" when the cache has not yet been bootstrapped.
func (*CacheImpl) RateLimitStats ¶
func (c *CacheImpl) RateLimitStats() (rest, graphql gh.RateLimitStats)
RateLimitStats always delegates to GitHub.
func (*CacheImpl) Reconcile ¶
func (c *CacheImpl) Reconcile(board *gh.ProjectBoard)
Reconcile replaces shallow board state from a fresh board fetch. Preserves deep fields (Comments, LinkedPRReviews, etc.) for items that have already been deep-fetched. Logs the drift count when items differ. Shallow drift in linkage (LinkedPRNumber) invalidates deep cache for the affected key, forcing a fresh FetchItemDetails on next access.
func (*CacheImpl) RecordPRLinkage ¶
RecordPRLinkage records an authoritative PR→issue mapping in the Store index. fullRepo must be in "owner/repo" format. Called by the engine immediately after CreateDraftPR succeeds, so all subsequent webhooks for this PR resolve to the correct issue without consulting the regex. No-op when the mapping is already present (avoids clobbering real webhook data) or when the issue is not yet in the Store (cold-cache bootstrap not yet complete).
func (*CacheImpl) RefreshCheckRunsLive ¶ added in v0.0.76
RefreshCheckRunsLive unconditionally fetches check runs for sha from GitHub, bypassing FetchCheckRuns's cache-trust check entirely, and applies the result into the Store exactly as FetchCheckRuns's own miss path does — so a subsequent FetchCheckRuns call for the same sha is served from this fresh data.
#1303: this exists to close a narrow but real gap in FetchCheckRuns's general cache-trust contract (deliberately left unchanged — see its doc comment): a cached PENDING classification is served from cache indefinitely, since only a would-be-FAILED classification forces a live refetch (#958 leg 3). On a webhook-less deployment nothing else ever supersedes a stale cached PENDING snapshot with a check_run event, so settleAwaitingCIScan (the one caller for which an open-ended stale-Pending read is consequential — it can silently claim the item forever via checkMergeabilityGate's PRMergeUnsettled branch) calls this once per fabrik:awaiting-ci item per poll to prime the store with genuinely fresh data before the Phase 1 handler chain runs, rather than trusting whatever FetchCheckRuns' own cache-trust check would otherwise decide.
func (*CacheImpl) RegisterItemID ¶
RegisterItemID sets the project-item node ID for an existing cache entry that was added without one (e.g., via issues.opened before projects_v2_item.created). No-op when key is not in the Store or itemID is empty. Safe for concurrent use.
func (*CacheImpl) RemoveItem ¶ added in v0.0.75
RemoveItem removes the cached item identified by itemID (the GraphQL project-item node ID), mirroring the webhook delta path's "deleted"/"archived" handling (boardcache/delta.go). Used by the archive-done settle scan (engine/archive_done_settle.go) to write through a successful ArchiveProjectItem call so the cache stays consistent with GitHub's view without waiting for a webhook echo or the next Reconcile. No-op (not an error) when itemID is unknown — safe to call redundantly. Safe for concurrent use.
func (*CacheImpl) Resume ¶
func (c *CacheImpl) Resume()
Resume re-enables delta application (called after reconciliation on stream recovery). Observers are called after the lock is released, and only on an actual true→false transition to avoid spamming observers on repeated Resume calls.
func (*CacheImpl) SetMatchEchoFn ¶
SetMatchEchoFn injects the MatchEcho function from the webhook manager.
func (*CacheImpl) Subscribe ¶
Subscribe registers an observer on the underlying Store. The returned func unsubscribes the observer. Safe to call from any goroutine.
func (*CacheImpl) SubscribePause ¶
SubscribePause registers a function that is called after every Pause/Resume transition. The function receives true when the cache is paused and false when resumed. Observers run outside c.mu, so calling other CacheImpl methods from an observer is safe. Calling Pause or Resume re-entrantly from within an observer is semantically wrong (double-fire, inconsistent state) and must be avoided. The returned func unsubscribes the observer.
func (*CacheImpl) UpdateItemStatus ¶
UpdateItemStatus updates the Status field for the item identified by key. No-op when the key is not in the cache. Safe for concurrent use.
type GitHubAdapter ¶
type GitHubAdapter struct {
// contains filtered or unexported fields
}
GitHubAdapter wraps a ReadClient with pass-through implementations. Used as the fallback inside CacheImpl (cache miss → forward to GitHub) and directly in NewWithDeps test wiring (engine tests bypass CacheImpl).
func NewGitHubAdapter ¶
func NewGitHubAdapter(client ReadClient) *GitHubAdapter
NewGitHubAdapter wraps any ReadClient as a pass-through GitHubAdapter.
func (*GitHubAdapter) FetchCheckRuns ¶
func (a *GitHubAdapter) FetchCheckRuns(owner, repo, sha string) ([]gh.CheckRun, error)
func (*GitHubAdapter) FetchCombinedStatus ¶ added in v0.0.76
func (a *GitHubAdapter) FetchCombinedStatus(owner, repo, ref string) ([]gh.CommitStatus, error)
func (*GitHubAdapter) FetchItemDetails ¶
func (a *GitHubAdapter) FetchItemDetails(item *gh.ProjectItem) error
func (*GitHubAdapter) FetchLabels ¶
func (a *GitHubAdapter) FetchLabels(owner, repo string, issueNumber int) ([]string, error)
func (*GitHubAdapter) FetchLinkedPR ¶
func (*GitHubAdapter) FetchPRClosingIssues ¶
func (a *GitHubAdapter) FetchPRClosingIssues(owner, repo string, prNumber int) ([]int, error)
func (*GitHubAdapter) FetchPRMergeable ¶
func (a *GitHubAdapter) FetchPRMergeable(owner, repo string, prNumber int) (*bool, error)
func (*GitHubAdapter) FetchPRMergeableFields ¶ added in v0.0.70
func (*GitHubAdapter) FetchPRMergeableState ¶
func (a *GitHubAdapter) FetchPRMergeableState(owner, repo string, prNumber int) (string, error)
func (*GitHubAdapter) FetchPRMerged ¶ added in v0.0.70
func (a *GitHubAdapter) FetchPRMerged(owner, repo string, prNumber int) (bool, error)
func (*GitHubAdapter) FetchPRReviewDecision ¶ added in v0.0.76
func (a *GitHubAdapter) FetchPRReviewDecision(owner, repo string, prNumber int) (string, error)
func (*GitHubAdapter) FetchPRReviewRequests ¶ added in v0.0.75
func (a *GitHubAdapter) FetchPRReviewRequests(owner, repo string, prNumber int) ([]gh.ReviewRequest, error)
func (*GitHubAdapter) FetchPRReviews ¶ added in v0.0.75
func (*GitHubAdapter) FetchPRsForSHA ¶
func (a *GitHubAdapter) FetchPRsForSHA(owner, repo, sha string) ([]int, error)
func (*GitHubAdapter) FetchProjectBoard ¶
func (a *GitHubAdapter) FetchProjectBoard(owner, repo string, projectNum int, ownerType string) (*gh.ProjectBoard, error)
func (*GitHubAdapter) FetchProjectItem ¶
func (a *GitHubAdapter) FetchProjectItem(owner, repo string, issueNumber int) (*gh.ProjectItem, error)
func (*GitHubAdapter) FetchStatusField ¶
func (a *GitHubAdapter) FetchStatusField(projectID string) (*gh.StatusField, error)
func (*GitHubAdapter) RateLimitStats ¶
func (a *GitHubAdapter) RateLimitStats() (rest, graphql gh.RateLimitStats)
type ReadClient ¶
type ReadClient interface {
FetchProjectBoard(owner, repo string, projectNum int, ownerType string) (*gh.ProjectBoard, error)
FetchItemDetails(item *gh.ProjectItem) error
FetchCheckRuns(owner, repo, sha string) ([]gh.CheckRun, error)
FetchCombinedStatus(owner, repo, ref string) ([]gh.CommitStatus, error)
FetchLinkedPR(owner, repo string, issueNumber int) (*gh.PRDetails, error)
FetchPRMergeableFields(owner, repo string, prNumber int) (mergeable *bool, mergeableState string, err error)
FetchPRMergeable(owner, repo string, prNumber int) (*bool, error)
FetchPRMerged(owner, repo string, prNumber int) (bool, error)
FetchPRMergeableState(owner, repo string, prNumber int) (string, error)
FetchLabels(owner, repo string, issueNumber int) ([]string, error)
FetchStatusField(projectID string) (*gh.StatusField, error)
FetchPRClosingIssues(owner, repo string, prNumber int) ([]int, error)
FetchPRReviews(owner, repo string, prNumber int) ([]gh.PRReview, error)
FetchPRReviewRequests(owner, repo string, prNumber int) ([]gh.ReviewRequest, error)
FetchPRReviewDecision(owner, repo string, prNumber int) (string, error)
FetchPRsForSHA(owner, repo, sha string) ([]int, error)
FetchProjectItem(owner, repo string, issueNumber int) (*gh.ProjectItem, error)
RateLimitStats() (rest, graphql gh.RateLimitStats)
}
ReadClient is the subset of engine.GitHubClient covering read-only board/item/PR/check-run state. engine.GitHubClient is a strict superset; the concrete gh.Client satisfies this interface.