LearnNewsExamplesServices
Frontmatter
id12624
titleGitLabClient + real IssueService issue operations + tests
stateClosed
labels
enhancementaiarchitecturebuild
assigneesneo-opus-vega
createdAtJun 6, 2026, 9:02 AM
updatedAtJun 6, 2026, 3:42 PM
githubUrlhttps://github.com/neomjs/neo/issues/12624
authorneo-opus-vega
commentsCount2
parentIssue11404
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[ ] 12631 Real MergeRequestService merge-request operations + tests
closedAtJun 6, 2026, 3:42 PM

GitLabClient + real IssueService issue operations + tests

Closed v13.0.0/archive-v13-0-0-chunk-16 enhancementaiarchitecturebuild
neo-opus-vega
neo-opus-vega commented on Jun 6, 2026, 9:02 AM

Context

First implementation sub of #11404 (GitLab Workflow MCP Server — parity with gh-workflow). The scaffold sub #11768 is complete (MCP server + config + tool routing exist), but every gitlab-workflow service returns a {status: 'scaffolded'} placeholder — no real GitLab API behavior. @neo-gpt's epic-resolution review maps the BLOCKERs: no GitLabClient exists, services defer real behavior, and no gitlab specs exist. This sub delivers the foundational client + real IssueService issue operations + tests. Epic validated per gpt's resolution review (roadmap-fit: GitLab parity is an established Agent-OS tooling capability; approach: mirror gh-workflow; scaffold complete, implementation subs needed).

The Problem

ai/services/gitlab-workflow/ services (IssueService, MergeRequestService, LocalFileService) all return a private #scaffold() placeholder ({status:'scaffolded', message:'…real GitLab API behavior lands with the GitLabClient subtask'}). No GitLabClient exists anywhere, so the registered MCP tools are inert. No test/playwright/unit/ai/services/gitlab-workflow/ specs exist.

The Architectural Reality

The gh-workflow server's client layer is ai/services/github-workflow/GraphqlService.mjs — a GitHub-specific GraphQL client: query(query, variables) → PAT-auth (gh auth token) POST to https://api.github.com/graphql, with 429/502/503/504 retry + backoff. Services import it and call query() with constants from ./queries/*.mjs. GitLabClient must mirror this for GitLab, with the API differences:

Aspect GitHub (GraphqlService) GitLab (GitLabClient)
Endpoint https://api.github.com/graphql ${aiConfig.gitlab.hostUrl}/api/graphql
Auth Authorization: bearer <gh token> Authorization: Bearer <aiConfig.gitlab.token / NEO_GITLAB_PAT>
Root repository(owner,name) project(fullPath)
Issue id number iid (+ GraphQL id)
Comments comments.nodes notes.nodes

Config already exists: aiConfig.gitlab.hostUrl (NEO_GITLAB_HOST, default gitlab.com) + aiConfig.gitlab.token (NEO_GITLAB_PAT). HealthService is already partially real (config-presence check).

The Fix

Path Type Role
ai/services/gitlab-workflow/GitLabClient.mjs NEW GraphQL client singleton mirroring GraphqlService (query + Bearer auth + retry)
ai/services/gitlab-workflow/queries/issueQueries.mjs NEW GitLab issue GraphQL query constants (list, get)
ai/services/gitlab-workflow/queries/mutations.mjs NEW GitLab issue mutation constants (create, note add/update, labels, assignees)
ai/services/gitlab-workflow/IssueService.mjs MODIFY Replace #scaffold() with real ops via GitLabClient
test/playwright/unit/ai/services/gitlab-workflow/GitLabClient.spec.mjs NEW Client retry/auth/error tests (mock fetch)
test/playwright/unit/ai/services/gitlab-workflow/IssueService.spec.mjs NEW IssueService behavior tests (mock GitLabClient.query)
ai/services.mjs MODIFY Wire GL_IssueService (makeSafe + export), load glSpec from the gitlab openapi

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback / Edge Docs Evidence
GitLabClient.query(query, variables) This sub; GraphqlService.mjs pattern; GitLab GraphQL API PAT-auth POST to ${hostUrl}/api/graphql; returns json.data; retries 429/5xx with backoff; throws on auth/GraphQL errors Missing token/host → clear error (mirrors HealthService config check); GraphQL errors surfaced JSDoc GitLabClient.spec.mjs (mock fetch: success, retry, auth-fail, GraphQL-error)
IssueService issue ops (listIssues/createIssue/manageIssueComment/manageIssueLabels/manageIssueAssignees) This sub; the scaffold IssueService; the gh-workflow IssueService contract; openapi.yaml Real GitLab issue operations via GitLabClient, returning the MCP contract shapes the openapi defines Empty/no-project → graceful; mirror gh-workflow return shapes JSDoc + openapi IssueService.spec.mjs (mock GitLabClient: each op)

Decision Record impact

aligned-with ADR 0018 (which treats gitlab-workflow/ as a PoC excluded from the functional MCP-server count). This sub advances GitLab from scaffold-PoC toward functional but does NOT yet flip the classification (issues only, no MRs/sync) — a future full-parity sub updates ADR 0018. No ADR change here.

Acceptance Criteria

  • AC1: GitLabClient.mjs implements query(query, variables) — Bearer PAT auth from aiConfig.gitlab.token, POST to ${aiConfig.gitlab.hostUrl}/api/graphql, 429/5xx retry + backoff, returns json.data, throws a clear error on missing token/host or GraphQL errors.
  • AC2: IssueService real behavior for listIssues, createIssue, manageIssueComment, manageIssueLabels, manageIssueAssignees via GitLabClient (no remaining #scaffold() for those), handling GitLab iid + notes + project-root.
  • AC3: GitLabClient.spec.mjs (mock fetch: success / retry-on-5xx / auth-failure / GraphQL-error) + IssueService.spec.mjs (mock GitLabClient.query: each op) — both pass via npm run test-unit -- <specs>.
  • AC4: GL_IssueService wired in ai/services.mjs (makeSafe against the gitlab openapi); MCP tools dispatch to real behavior (toolService already wired).

Out of Scope

  • MergeRequestService real behavior — follow-up sub.
  • LocalFileService / issue-MR syncers / local cache — follow-up sub.
  • package.json ai:mcp-server-gitlab-workflow script + broader docs + ADR 0018 PoC-reclassification — follow-up (epic residual per gpt's review).
  • Live GitLab API integration test (no test GitLab project in CI) — unit-mock only here.

Avoided Traps

  • Shelling out to a glab CLI. Rejected — mirror GraphqlService's direct HTTP-GraphQL approach (no new CLI dependency).
  • Hardcoding the GitLab project path. Use config/options (project path/id), mirroring how gh-workflow uses owner/repo from config.
  • Reusing/generalizing GitHub's GraphqlService. GitLab's endpoint + schema (project/iid/notes) differ — a dedicated GitLabClient is correct, not an over-abstraction of two different APIs.

Related

  • #11404 (parent epic), #11768 (scaffold sub).
  • Pattern source: ai/services/github-workflow/GraphqlService.mjs + IssueService.mjs + test/playwright/unit/ai/services/github-workflow/IssueService.spec.mjs.
  • Epic-validation: @neo-gpt's #11404 resolution review.

Origin Session ID: a54e89a3-4259-4b41-9e26-561f665de744

Retrieval Hint: "GitLabClient GraphQL client gitlab-workflow IssueService real behavior"; mirror github-workflow GraphqlService pattern.

tobiu referenced in commit bd3e243 - "feat(ai): real GitLab IssueService — GitLabClient + issue ops (#12624) (#12625) on Jun 6, 2026, 3:42 PM
tobiu closed this issue on Jun 6, 2026, 3:42 PM