Files
2026-09-23 13:31:12 +01:00

11 KiB

status, system, requirements
status system requirements
draft integrations
REQ-INTEGRATIONS-GITHUB-WORKFLOW-ATTENTION-002
REQ-INTEGRATIONS-GITHUB-WORKFLOW-ATTENTION-001

GitHub Workflow Attention System Design

Purpose and boundaries

Workflow attention supplements check results. It does not rewrite GitHub mergeability or manufacture check runs. The integration owns collection, storage, and interpretation. Existing shared components own presentation geometry.

Requirement mapping

Acceptance criteria Design sections
001.1, 001.6, 001.7 Provider evidence
001.2, 001.4 Status and automation
001.5 Storage and recovery
001.3, 001.8 Presentation

All criteria reference AC-INTEGRATIONS-GITHUB-WORKFLOW-ATTENTION.

Provider evidence

Add a workflow-run reader to Client, GHClient, and PATClient, with matching mock and noop implementations. Use the repository Actions runs endpoint with an exact head_sha and pagination. Use the existing workspace credential and timeout policy. Never fall back to another identity after permission denial.

Keep workflow ID, run ID, attempt, event, head SHA, head repository, branch, conclusion, and HTML URL. Select the newest run and attempt for each workflow, event, and source branch/repository identity. Ignore earlier attempts and runs that a newer execution supersedes. Do not filter to action_required before selecting the latest runs.

Match explicit pull-request associations when present. Use the association repository ID and canonical repository URL when the REST payload omits owner.login, and compare every identity field that both the association and pull-request transport provide. A mismatching non-empty association or top-level head repository excludes the run. GitHub can return an empty association list for fork workflows that require approval. For that case, require matching head SHA, head repository, head branch, and the pull_request event. Extend the PR transport shape with head repository identity where necessary.

For selected action_required runs, fetch current-attempt job counts. A completed fork pull_request run with action_required and no jobs supplies the approval classification for this defect. This is an interpretation of combined provider evidence, not an explicit approval-reason field. Other action-required runs use the generic attention classification. Unknown job counts must not become zero. Missing runs, waiting, and UNSTABLE alone never prove approval.

getPRStatus and getPRFeedback in client_helpers.go share the collector and classifier. The batched service path in service_pr_watch_batched.go enriches statuses before caching and applying them. Cover both numbered and branch-discovered watches. The existing poller owns refresh cadence. Coalesce enrichment by credential scope, repository, and head identity within each sync. Use bounded concurrency and the existing context budget. Do not add a frontend poller or one request per mounted surface. The unwatched-task lifecycle sweep only reconciles PR state, the observed head, and stored workflow attention; it does not issue new Actions reads. Retained watches and REST feedback/status paths provide fresh workflow evidence, while a head change invalidates the stored observation.

The REST workflow runs contract defines collection and permission requirements. GitHub documents the maintainer action in Approving workflow runs from forks.

Data contract

Add an additive workflow_attention object to PRStatus, PRFeedback, and TaskPR:

state: unknown | none | approval_required | action_required
head_sha: observation identity
observed_at: timestamp of successful observation
stale: whether the most recent attempted observation failed
runs: [{run_id, run_attempt, workflow_id, name, url, reason}]

The run list contains only selected workflows that need attention. none requires complete provider evidence. Partial or unavailable evidence is unknown unless a prior same-head observation exists. An internal populated marker distinguishes old callers that did not attempt collection from an observed unknown result. When a surface has both stored TaskPR evidence and cached feedback, compare applicable same-head observations by observed_at and retain none as an authoritative observation during that comparison. A changed-head or malformed cached observation cannot hide valid current stored evidence; a newer unknown observation preserves a positive result as stale. Old payloads without this object remain compatible and cannot claim approval.

Storage and recovery

Persist the object as one JSON text column on github_task_prs, with an empty default for existing rows. Use the existing additive migration, column list, scan, upsert, update, and restore paths. SyncTaskPR remains the writer and publishes the existing workspace-scoped github.task_pr.updated event. Boot data, task-scoped reads, feedback persistence, and live events carry the same object. Keep compact task-list projections bounded. Derive their attention category from the stored object rather than adding the run list.

An unavailable read preserves prior same-head evidence and marks it stale. The UI shows "Last known" and a refresh-unavailable explanation for that evidence. A new head invalidates old evidence immediately. Closed or merged PRs suppress active attention. An authoritative complete read replaces the run list, including an explicit empty result. Omitted legacy observations preserve same-head stored evidence and never clear it accidentally.

Actions read permission can be absent even when check reads succeed. Permission errors, rate limits, and timeouts leave other PR data available. They do not trigger permission changes or claim that CI passed. Bounded debug logs name the operation and PR, without tokens or response bodies.

Status and automation

Leave actual checks_state, checks_total, and checks_passing intact. Do not insert workflow placeholders into CheckRun or existing failure snapshots. Approval-only evidence produces no CI repair message and consumes no repair round. Existing independent review/comment/conflict triggers retain their behavior. Actual failed checks remain eligible for their existing repair path.

The strict merge predicate rejects current attention, including stale positive evidence for the same head. Preserve the reviewed-head invariant in the auto-merge ADR. Display precedence remains terminal, active queue, draft, actual blocking failures, then workflow attention before success. An approval row remains visible alongside independent failure rows.

Presentation

pr-task-status-summary.tsx adds a warning CI row: "Awaiting maintainer approval". For approval-only evidence, suppress the redundant raw unstable merge row. For unexplained unstable, use localized "Checks not successful" without inventing a cause. Retain raw fallback behavior for genuinely unrecognized provider values.

pr-task-icon.tsx and pr-status-chip.tsx consume one shared attention interpretation. Audit the GitHub registered-provider adapter and compact task projection so active and inactive rows agree. pr-ci-popover.tsx and pr-detail-panel.tsx show the workflow name, reason, and "View on GitHub" link. Do not show "No checks" as the sole explanation or offer "Fix CI" for approval-only evidence. Use the existing provider-neutral summary and detail anatomy. Avoid GitHub-specific slots in shared primitives. All new copy uses locale keys in English, Portuguese, and the three Chinese catalogs.

The phone entry remains task navigation, then the PR status chip. Reuse PRStatusChipDrawer and its existing scroll owner, safe areas, and dismiss behavior. The closest shipped exemplar is e2e/tests/pr/mobile-pr-ci-chip.spec.ts and its corresponding chip component. The compact task-row icon stays passive on touch. No new drawer or nested overlay is necessary. The external link has a 44px minimum touch hit area, while desktop density stays unchanged.

Verification

Provider fixtures reproduce an empty check rollup with a jobless action-required fork workflow. Mixed-state tests cover an approval gate alongside a real failure and alongside a successful workflow. Recovery tests cover newer attempts, changed heads, permission errors, reloads, and REST/GraphQL convergence. Component tests cover summary copy, counts, status precedence, and strict merge readiness. Desktop and mobile Playwright tests verify the existing entry points and the provider link.

Expiring Actions observations

REQ-INTEGRATIONS-GITHUB-WORKFLOW-ATTENTION-002 maps to this section. Share raw workflow-run observations across batched enrichment and service feedback/status reads. Keep per-PR classification outside the shared cache. Key entries by credential scope and generation, normalized repository identity, and head SHA. Reuse the bounded ttlCache and its singleflight/invalidation patterns; add per-entry expiry support if needed. Keep at most 512 run entries and 512 job entries. Errors are not cached.

Observation TTL
Empty list or any pending/running/unknown status 30 seconds
Any approval/action-required or ambiguous attention result 30 seconds
Nonempty, all completed, no attention requirement 5 minutes

A SHA does not freeze the workflow run collection. Reruns and new runs can arrive for the same SHA. Never use an infinite TTL. Cache job observations by credential scope, repository, run ID, and attempt, with the same expiry classes. A run-attempt change must not reuse jobs from an earlier attempt.

Keep existing batched enrichment limits: concurrency 4 and total budget 5 seconds. Preserve the outer status/search cache TTL of 30 seconds and the feedback TTL of 8 seconds. Long Actions entries only affect workflow attention, not checks, review status, or auto-merge decisions.

Explicit refresh invalidates the relevant Actions and outer response entries, then coalesces concurrent refreshes. Generation checks prevent an older in-flight request from repopulating invalidated data. Passive page polling uses the cache. Route future approval/rerun mutations through this invalidation seam; adding those mutations is outside this package.

External reruns on a completed SHA can take up to 5 minutes plus the next 1-minute poll tick to appear. Attention and running results use the short TTL. Provider errors retain unknown/stale-positive semantics and existing retry admission. Terminal PRs continue to skip Actions reads altogether.

See the implementation plan.