Files
kandev/docs/specs/integrations/system-design/gitlab-integration-02.md
T
2026-08-24 11:09:03 +00:00

186 lines
10 KiB
Markdown

---
status: draft
system: integrations
requirements:
- REQ-INTEGRATIONS-GITLAB-INTEGRATION-001
created: 2026-05-04
updated: 2026-08-05
owners:
- tbd
---
# GitLab Integration System Design Part 2
## Purpose and boundaries
This design preserves the technical source detail for `REQ-INTEGRATIONS-GITLAB-INTEGRATION-001` during migration.
## Requirement mapping
| Requirement | Design section |
| --- | --- |
| `REQ-INTEGRATIONS-GITLAB-INTEGRATION-001` | [Migrated source detail](#migrated-source-detail) |
## Migrated source detail
## Failure modes
- Saving an invalid host or credential fails without replacing the last known
working connection or secret.
- A transient health or API failure keeps the saved config and linked/watch
records. The UI shows an unavailable state and allows retry; pollers back off
and do not create tasks from incomplete results.
- Revoked credentials mark only the affected workspace `auth_required` and
pause API work for it until a successful probe. Other workspaces continue.
- Watch dispatch reserves the external item before creating a task. Task-create
or auto-start failure releases or completes the reservation according to the
shared watcher dispatcher, preventing both lost matches and duplicate tasks.
- A deleted/soft-deleted watch dependency self-disables the watch with a visible
error instead of creating an orphan task.
- Link creation is atomic from the user's perspective: if URL validation or MR
fetch fails, no association is written. Repeating a successful request
returns the existing association.
- Unlink failure leaves the association and refresh watch intact. Unlink never
closes or unsubscribes from the upstream MR.
- Watch delete is best-effort for owned-task cleanup: individual task-delete
failures are logged, remaining owned tasks are attempted, and the watch/dedup
rows are removed. It never schedules another poll.
- Watch reset follows the shared GitHub `watchreset` contract: after preview and
confirmation it best-effort attempts every owned task deletion (including
archived), logs and continues past individual task-delete failures, then
transactionally clears dedup and `last_polled_at`. A clear failure surfaces
together with the count already deleted; otherwise the response reports the
successful delete count. Review watches rerun immediately and issue watches
are eligible on their next poll/run-now.
- Reviewer, discussion, merge, and subscription failures leave the last fetched
UI state visible and show an action error; the UI refreshes after success.
- MR creation never retries against another host. A successful push followed by
a failed MR request is reported as partial failure with the pushed branch
intact so the user can retry without another commit.
## Persistence guarantees
- Workspace config rows, PAT secrets, watch definitions, dedup reservations,
task-to-MR associations, and last known MR status survive backend restarts.
- Archived tasks retain task-to-MR associations for later unarchive; hard task
deletion removes task-owned associations and refresh watches.
- The startup migration moves the legacy global host/token to the active
workspace, or the earliest-created workspace when no active workspace is
available. It is idempotent and never duplicates automation watches.
- `glab` login and `GITLAB_TOKEN` remain host-process state and are not copied or
backed up by Kandev.
- In-flight HTTP requests and poll iterations do not resume after restart. The
next health/poll cycle re-runs safely against durable dedup state.
- GitLab notification subscriptions survive because GitLab owns them; Kandev
re-reads their state after reload.
## Scenarios
- **GIVEN** two workspaces connected to different GitLab hosts, **WHEN** each
opens its GitLab page, **THEN** each sees only data fetched with its own host
and credential.
- **GIVEN** a workspace without a GitLab connection, **WHEN** the user enters a
public `gitlab.com` repository URL in Remote task creation, **THEN** Kandev
lists its branches anonymously without making any other GitLab browse or
write capability available.
- **GIVEN** a legacy global GitLab host and token, **WHEN** Kandev starts after
upgrade, **THEN** one deterministic workspace receives the config and secret
and other workspaces remain unconfigured.
- **GIVEN** a self-managed workspace connection, **WHEN** a user links a valid
MR URL from that host, **THEN** the task shows the linked MR and its live
review details after reload.
- **GIVEN** a task with no linked MR in a GitLab-configured workspace, **WHEN**
the task detail opens, **THEN** the top bar has no `Link MR` action and the
task's contextual `Link` submenu offers `GitLab Merge Request`.
- **GIVEN** a touch viewport and a task with no linked MR in a GitLab-configured
workspace, **WHEN** the user opens the task row's visible actions menu and
chooses `Link` then `GitLab Merge Request`, **THEN** the GitLab MR link dialog
opens without relying on right-click or long press.
- **GIVEN** a task with a linked GitLab MR, **WHEN** the task detail opens,
**THEN** the top bar shows the linked MR status control rather than a generic
link action.
- **GIVEN** an MR URL from a different host, **WHEN** it is linked in the current
workspace, **THEN** the request is rejected and no association is written.
- **GIVEN** a linked MR, **WHEN** the user unlinks it, **THEN** it disappears
from the task and GitLab list indicator while the upstream MR is unchanged.
- **GIVEN** a GitLab MR or issue search row, **WHEN** the user launches a preset,
**THEN** the task-create dialog is prefilled with the matching project and
context and successful creation navigates to the task.
- **GIVEN** a linked MR with discussions, approvals, conflicts, and a pipeline,
**WHEN** the user opens its task review panel, **THEN** all states and thread
actions are available without leaving Kandev.
- **GIVEN** an eligible project member, **WHEN** the user selects them as a
reviewer, **THEN** GitLab and the refreshed MR panel both show that reviewer.
- **GIVEN** a linked MR with auto-fix enabled, an open state, a settled
failing pipeline, and a promptable session, **WHEN** automation evaluates
the MR, **THEN** it sends or queues exactly one `@mr-auto-fix` prompt and
`auto_fix_round_count` increments by one; an unchanged snapshot on the next
evaluation dispatches nothing.
- **GIVEN** a linked MR with auto-merge enabled and every readiness gate
satisfied, **WHEN** automation evaluates the MR, **THEN** Kandev merges it
exactly once, routed through the workspace client resolved with the linked
row's own host; a host mismatch never merges.
- **GIVEN** a linked MR reaches `merged`, `closed`, or `locked`, **WHEN**
auto-fix is still enabled, **THEN** no further auto-fix prompt is
dispatched for that MR.
- **GIVEN** a task with exactly one linked MR on desktop, **WHEN** the user
hovers the topbar button past the open delay, **THEN** a preview popover
shows the pass-rate bar, approval row, unresolved-discussions row,
Automation controls, a merge action when ready, and link/open/unlink
actions, all without a click.
- **GIVEN** a task with exactly one linked MR on desktop, **WHEN** the user
clicks the topbar button, **THEN** the MR detail panel opens directly (no
dropdown) and any open hover popover closes.
- **GIVEN** a task with two or more linked MRs, or any touch/coarse-pointer
viewport regardless of MR count, **WHEN** the user interacts with the
topbar button, **THEN** no hover popover is ever rendered and
clicking/tapping opens the existing per-MR dropdown.
- **GIVEN** a task with two linked MRs, one merged and one open with a failing
pipeline, **WHEN** the Kanban card renders its MR badge, **THEN** the badge
shows a count of two and the open MR's (red) colour, not the merged MR's.
- **GIVEN** an MR or issue the user does not subscribe to, **WHEN** they enable
notifications, **THEN** GitLab reports it subscribed and no Kandev watch or
task is created.
- **GIVEN** an enabled review watch, **WHEN** a new matching MR requests the
user as reviewer, **THEN** one linked task is created in the configured step
and auto-starts with the configured profiles when requested.
- **GIVEN** an enabled issue watch, **WHEN** a matching issue appears, **THEN**
one task is created with the issue URL and interpolated issue context.
- **GIVEN** a paused watch, **WHEN** scheduled polling or run-now occurs,
**THEN** no task is created and existing dedup state is retained.
- **GIVEN** a watch with owned tasks, **WHEN** the user previews and confirms
reset, **THEN** all shown tasks are attempted, the response reports successful
deletions, dedup state is cleared, the watch remains enabled, and currently
matching items can create new tasks immediately (review) or next poll (issue).
- **GIVEN** a watch with owned tasks, **WHEN** the user deletes the watch,
**THEN** Kandev best-effort deletes those tasks and removes the watch/dedup
state without recreating tasks from current matches.
- **GIVEN** a watch whose bound profile or repository was deleted, **WHEN** a
match is dispatched, **THEN** the watch disables with a visible error and no
orphan task is created.
- **GIVEN** a GitLab task branch with committed changes, **WHEN** the user
creates a draft merge request, **THEN** the branch is pushed to the configured
host, the returned MR URL is linked to that task repository, and the UI uses
merge-request terminology on desktop and mobile.
- **GIVEN** a revoked token in Workspace A, **WHEN** health polling runs,
**THEN** Workspace A shows `auth_required`, its watches stop dispatching, and
Workspace B continues using its own connection.
## Out of scope
- GitLab webhook ingestion; this iteration uses polling.
- Durable GitLab issue-to-task linking, issue state synchronization, or
Jira/Linear-style structured issue import.
- Editing GitLab approval rules, protected branches, CI configuration, pipeline
jobs/logs, or merge request templates.
- Group-wide dashboards beyond results visible to the configured user.
- OAuth-based Kandev sign-in, GitLab Duo, repository migration between hosts,
and Bitbucket parity.
- Multiple named GitLab connections inside one Kandev workspace.
- A multi-MR aggregate hover preview (the popover only covers the single-MR
topbar case; a task with 2+ linked MRs keeps the existing click-only
dropdown).
- GitLab's per-reviewer `requested_changes` states as a three-way review
label; "awaiting review" is approvals-count-based only (version/tier
dependent otherwise).
- Per-job CI log tailing in the auto-fix prompt.