Skip to main content

AI-Assisted GitHub Issue Resolution

How Cursor resolves a GitHub Issue in this repository: a strict, auditable workflow with mandatory human validation before merge. The binding rule is .cursor/rules/github-issue-resolution.mdc; this page explains the same process for humans.

Why this exists

We want Cursor to be able to take a GitHub Issue end-to-end — read it, investigate, propose a fix, implement it, open a PR — without ever merging code on its own or working directly on a protected branch. Every implementation is gated behind two public comments (analysis + proposal) and an explicit uncertainty check. If Cursor is not confident, it stops and asks instead of guessing.

How to invoke it

From Cursor

Resuelve https://github.com/GekkotechSL/UPPV4_APPLICATION/issues/123

or in English:

Resolve https://github.com/GekkotechSL/UPPV4_APPLICATION/issues/123

Any phrasing that clearly asks Cursor to resolve/fix/implement a GitHub Issue, or references an issues/<n> URL, activates the rule.

From GitHub

@cursor resuelve esta incidencia siguiendo el workflow del repositorio
note

@cursor mentions on GitHub only work if the Cursor GitHub App / background-agent integration is installed and connected for this repository (Cursor dashboard → Integrations → GitHub). That connection is an external, one-time setup step and is not part of this repo's files — see GitHub configuration still required. Until it is connected, use the "From Cursor" form above, or run the same prompt inside a Cursor session with gh access to this repo.

What Cursor uses to talk to GitHub

Preference order (see the rule for exact scope):

  1. Cursor's GitHub/MCP integration, if configured in the session.
  2. GitHub CLI (gh), authenticated — this is the mechanism verified and available today for this repo (repo, workflow, read:org scopes). Used to read issues/comments/labels, post comments, add labels, and create PRs.
  3. If neither is available, Cursor stops and states exactly what's missing instead of guessing or asking for a pasted token.

Cursor never prints, logs, or commits GitHub tokens, and never stores credentials inside the repository.

The phases

PhaseWhat happensCan Cursor write code/commits?
0 — Read & investigateReads the issue (title, description, labels, all comments), Project field Rama, related issues/PRs, and the relevant code/tests/rules. Resolves <rama-app> (UPPV4_APPLICATION base).No
0b — IncompleteIf Rama is missing/unusable (e.g. only e2e/base with no app branch): post ## ⛔ Incomplete report, add incomplete, set Project Status to Ready, STOP.No
1 — Analysis commentPublishes a ## 🔎 Analysis comment: problem summary, expected vs. actual behaviour, likely root cause + confidence level, affected files, assumptions, risks, existing/needed tests.No
1b — Invalid dispositionIf analysis concludes (high confidence) there is no valid defect: add invalid without removing existing labels, set Project Status to Ready, STOP. No proposal, no code, no PR. Cursor never closes/reopens the issue.No
2 — Implementation proposalPublishes a ## 🛠 Implementation proposal comment: proposed solution, steps, files to touch, tests, backwards compatibility, migrations, security implications, risks, edge cases, definition of done. Skipped when disposition is invalid.No
3 — Uncertainty gateExplicitly checks for material doubts (see below).No
4 — Worktree + branchCreates/reuses a git worktree at .worktrees/issue-<n> with a dedicated branch from origin/<rama-app>. Must not checkout/switch/stash the developer's primary workspace checkout.No (worktree setup only)
5 — ImplementationImplements the smallest solution consistent with the published proposal; adds/updates tests — only inside the issue worktree.Worktree only
6 — ValidationRuns the project's tests/lint/type-check/build (and PHPUnit/php -l when touching server/**) inside nx-dev / docker/pw with cwd /app/.worktrees/issue-<n> (so Docker's /app mount sees the fix). FAIL blocks progress.Worktree only
6b — Quality gateBlocking pre-commit. Opens and applies stack rules: Angular devil-advocate (APTO) + done-is-done + preconditions; PHP backend/devil-advocate (FIT) + backend/done-is-done + PHPUnit/coverage/_CHANGESLOG. FAIL → Phase 5.Worktree only
7 — Self-reviewReviews the full diff before committing (no accidental files, no secrets, matches the published proposal, Phases 6+6b PASS).Worktree only
7b — Pre-commit commentPosts ## ✅ Pre-commit quality gate on the issue with PASS evidence (Devil's Advocate + done-is-done + Fase 6 commands). Required before any commit/PR.No code
— Commit & pushCommits and pushes only the dedicated branch from the worktreeonly if Phase 7b is PASS.Yes (scoped exception, see below)
8 — Pull RequestOpens a PR against <rama-app> only if the pre-commit quality gate comment is PASS; cites that evidence in Validation; sets QA Project Status to In progress.Yes (PR creation only)
— Human gateSTOP. No merge, no auto-merge, no self-approval. Issue stays open until QA closes it.Never

One PR per issue (lifecycle)

Team policy for Quality Assurance issues:

  1. One Pull Request per issue. Follow-up work (QA rejection, extra commits) always continues on the same PR / dedicated branch. Do not open a second PR for the same issue.
  2. Merge does not end the issue. Humans may merge the PR into <rama-app> when ready; the issue stays open and the Project stays In progress until QA validates.
  3. Do not use Fixes # / Closes # in the PR body — use Related to #<n> (or Addresses #<n>) so merge does not auto-close the issue. QA closes the issue after validation → Status Done.
  4. PR cleanup happens from Done only. Deleting the head branch / housekeeping the (possibly already merged) PR is done when the item is in Done, not right after merge and not by Cursor in Phase 8.

Cursor checks for an existing PR before gh pr create and reuses it when present.

Required QA field: Rama

Every issue resolved by this workflow must include a usable test/application branch. Cursor reads it from:

  1. Project Quality Assurance → field Rama (preferred),
  2. otherwise the issue body/comments (Rama:, Branch:, or última rama UPPV4_APPLICATION integrada: …).

Typical QA value:

e2e/base commit <sha> (última rama UPPV4_APPLICATION integrada: feature/<name>)

  • e2e/base / testing-repo SHAs are reproduction context.
  • The fix/PR base is the UPPV4_APPLICATION branch named after integrada: (or a plain app-branch name if that is all that was provided).
  • If the field is missing, empty, only names e2e/base without an app branch, or names a branch that does not exist on origin → disposition incomplete (below). Cursor must not fall back to master.

When incomplete is used

If Phase 0 cannot resolve a usable <rama-app>:

  1. Posts a ## ⛔ Incomplete report comment explaining what is missing and the expected format.
  2. Adds the incomplete label (without removing existing labels).
  3. Returns the item to QA when it is on Project Quality Assurance: Status → Ready.
  4. Does not post Analysis/Proposal, does not change product code, does not open a PR.
  5. Stops.

After QA fills Rama and the workflow is re-invoked, Cursor removes incomplete (only once the data is usable) and continues from Phase 0.

Quality Assurance project board (Status)

When the issue is on Project Quality Assurance, Cursor updates Status as part of the workflow:

SituationStatus
incomplete (rejected / returned for missing Rama)Ready
invalid (not a defect)Ready
PR opened/updated and waiting for human review + QAIn progress
Issue closed by QA after validationDone (human / board automation — never Cursor)

Done is not “PR merged”. Merge may happen earlier; Done means QA closed the issue. Clean up the PR from the Done column (delete head branch, etc.) — not while the item is still In progress.

When invalid is used

If Phase 1 concludes with high confidence that the report is not a valid defect — for example the observed UI is the designed mobile flow (form first, canvas behind a header toggle), the "root cause" cited in the bug template is intentional contract, or QA/reporter already confirmed there is no bug — Cursor:

  1. States that disposition clearly in the ## 🔎 Analysis comment (expected behaviour, code/test references, why no fix).
  2. Adds the invalid label (already in this repo's label set: "This doesn't seem right") without removing or replacing any labels the issue already has (bug, documentation, etc.). Typical command: gh issue edit <n> --add-label "invalid".
  3. Sets Project Status to Ready when the issue is on Quality Assurance.
  4. Does not post an implementation proposal, does not change product code, does not open a PR, and does not close or reopen the issue (closing remains human).
  5. Stops.

If confidence that it is "not a bug" is only medium/low, Cursor must not use invalid: continue to proposal / uncertainty gate, or use help wanted when a product decision is required.

When help wanted is used

If, at the uncertainty gate (or later, mid-implementation), Cursor finds a material doubt — something that could change user-visible behaviour, business/product logic, API contracts, data format, storage/schema, permissions, security, backwards compatibility, migration strategy, architecture, or acceptance criteria — it:

  1. Adds the help wanted label (already present in this repo's label set).
  2. Posts a ## ❓ Blocking questions comment with specific, answerable questions (e.g. "When X happens, should the endpoint return 404 or 200 with an empty collection?" — never a generic "what do you want me to do?").
  3. Stops and waits. It never invents an answer to keep going.

The same happens if new information invalidates the published proposal during implementation: Cursor stops, keeps any local changes safely on the dedicated branch, and asks before continuing.

Pre-commit quality gate before a PR can open (Phases 6 + 6b + 7b)

Passing tests alone is not enough. Before any commit or PR, Cursor must complete all three layers and get an explicit global PASS:

  1. Phase 6 — run the applicable executable checks in nx-dev / docker/pw (unit/integration/E2E, lint, type-check, build, php -l / PHPUnit / coverage). Record real PASS/FAIL. Any FAIL blocks progress.
  2. Phase 6b — open and apply the stack Definition of Done pipeline:
    • Angular/TypeScript (apps/**, libs/**): unpispas-preconditions.mdc; .cursor/rules/angular/devil-advocate.mdc → explicit APTO; then .cursor/rules/angular/done-is-done.mdc (compile, RF-*/RV-*/CA-* tests, coverage thresholds, functional-coverage audit cumple, entregable .mdc / Gobierno de cambios, no production-only-for-tests code, unused i18n keys, desktop/mobile when applicable).
    • PHP (server/**): .cursor/rules/backend/devil-advocate.mdc → explicit FIT; then .cursor/rules/backend/done-is-done.mdc (dedicated tests, PHPUnit PASS, coverage, _CHANGESLOG when applicable, server/tests/README.md, context docs sync) plus phptests-bestpractices.mdc / slimphp-bestpractices.mdc / backend context rules.
    • Mixed diffs must PASS both stacks.
  3. Phase 7b — publish a ## ✅ Pre-commit quality gate comment on the issue with the evidence and the line Gate global: PASS — se procede a commit/PR. Without this PASS comment, commit/push/gh pr create are forbidden in this workflow.

A FAIL on any layer sends the work back to Phase 5. Cursor must not open a PR with a missing or failing gate, and must not patch around a gate finding just to make it pass (product/architecture decisions become help wanted). The PR Validation section must cite the Phase 7b comment.

How the flow continues after a human answers

Once a human answers the blocking questions in the issue (as a comment, or by removing help wanted and/or replying), re-invoke the same prompt (Resuelve https://github.com/.../issues/<n>). Cursor re-reads the issue — including the new answers — re-runs the uncertainty gate, and either proceeds (Phase 4 onward) or asks again if the answer still leaves a material gap.

How the Pull Request is created

Before opening a PR, Cursor checks whether the issue already has one. If so, it reuses that PR (same dedicated branch) — one PR per issue.

Otherwise the PR is opened against <rama-app> from the QA Rama field (not blindly against the default branch). After a successful gh pr create (or when resuming the existing PR), Cursor sets Quality Assurance Status to In progress. The PR body uses .github/pull_request_template.md: Issue (Related to #<n>not Fixes/Closes, so merge does not auto-close the issue), Summary, Root cause, Base branch, Implementation, Validation (with real PASS/FAIL results, including the Phase 6b quality gate — never claimed without having run it), Manual validation, Risks, and Notes for reviewer.

Why merge is always manual

Cursor is deliberately never granted merge authority: no merge, no squash-merge, no rebase-merge, no auto-merge, no self-approval, no skipping required reviews/checks, no editing branch protections. After Phase 8 the correct state is "one PR for the issue, ready for human review/merge; issue remains open until QA closes it." Approval and merge are exclusively a human responsibility; closing the issue is exclusively QA; PR cleanup happens from the Done column.

This mirrors the repository-wide .cursor/rules/developer-only-git-operations.mdc policy (staging/history/remote are human-only). github-issue-resolution.mdc defines the only scoped exceptions to that policy: (1) for disposition incomplete, comment + incomplete label + Project Status Ready; (2) for disposition invalid, comment + labels + Project Status Ready; (3) for a valid fix after Phases 6+6b+7b PASS, commit/push/gh writes limited to the dedicated issue branch in .worktrees/issue-<n> (from origin/<rama-app>, without touching the developer's primary checkout), opening or updating the single PR with --base <rama-app>, and Project Status In progress — never merging, never closing the issue, never cleaning the PR before Done.

Parallel work: issues vs. in-progress development

QA may report a bug on branch feature/foo while you are actively developing on feature/bar with local uncommitted changes. Cursor must keep those worlds separate:

DoDo not
git worktree add .worktrees/issue-<n> -b fix/issue-<n>-… origin/<rama-app>git checkout / switch away from your current branch in the main workspace
Edit/test/commit only under .worktrees/issue-<n>git stash your WIP so the agent can change branches
In nx-dev: cd /app/.worktrees/issue-<n> && npx nx …Run validations against /app (primary checkout) when the fix lives in the worktree

Worktree directories stay gitignored (dot-path under .*). Remove them when the issue reaches Done (or when you ask), not as part of opening the PR.

GitHub configuration still required

This repository is on a GitHub Free organization plan (private repo). Branch protection and Rulesets APIs currently return 403 Upgrade to GitHub Pro, so they cannot be configured from this repo/CLI today. When the plan allows it, an administrator should configure, on the default branch (master):

  • Require a pull request before merging.
  • Require at least one human approval.
  • Require status checks to pass before merging (once CI workflows exist under .github/workflows/; none exist yet in this repo).
  • Disallow force-pushes on the default branch.
  • Disallow direct pushes to the default branch (require the PR flow even for admins, if acceptable for the team).

Until that is enabled, the enforcement is: (a) this rule + Cursor's behaviour, and (b) humans never merging a Cursor PR without review. allow_auto_merge is already false at the repository level; nothing was changed there.

If you want @cursor mentions to work directly on GitHub issues/PRs, install and connect the Cursor GitHub App for this repository from the Cursor dashboard (Integrations → GitHub) — that step happens outside this repo and could not be completed from here.

Troubleshooting

SymptomLikely causeFix
Cursor says it can't read/comment on the issuegh not authenticated in the session, or no GitHub/MCP integration configuredRun gh auth status; re-authenticate with gh auth login if needed (never paste a token into a repo file)
gh label create "help wanted" ... / "invalid" ... / "incomplete" ... failsMissing permissions on the repoAsk an admin to create the label once; report this explicitly in the issue instead of skipping the label
Cursor marks the issue incomplete and stopsMissing/unusable Project field Rama (or only e2e/base without an UPPV4_APPLICATION branch)QA fills Rama with the app branch under test (see format above), then re-invoke the workflow
PR creation failsNo push access to a personal fork / branch, or repo requires a different base branch nameConfirm the real default branch (gh repo view --json defaultBranchRef) and that gh has repo scope
@cursor on GitHub does nothingGitHub App integration not installed/connected for this org/repoConnect it from the Cursor dashboard, or use the "From Cursor" invocation instead
Cursor implemented code without posting Analysis/Proposal firstThe rule wasn't triggered (phrasing didn't mention an issue/URL) or was skippedRe-run with an explicit issue URL; if it happens again, treat it as a bug in the rule and fix .cursor/rules/github-issue-resolution.mdc
Cursor opened a PR without ## ✅ Pre-commit quality gatePhase 7b skippedClose or hold the PR for human review; treat as workflow bug — no merge until gate evidence exists on the issue
Agent stashed WIP or switched the main checkoutPhase 4 isolation violatedRestore stash / return to your branch; re-run the fix from .worktrees/issue-<n> only — treat as workflow bug
Tests in nx-dev do not see the fixValidations ran in /app instead of /app/.worktrees/issue-<n>Re-run with cwd set to the issue worktree inside the container

See also

  • .cursor/rules/github-issue-resolution.mdc — the binding rule (single source of truth for the exact phase-by-phase behaviour).
  • .cursor/rules/developer-only-git-operations.mdc — general git/GitHub policy and the scoped exception.
  • .cursor/rules/docker-dev-environment.mdc — where validations must run.
  • .cursor/rules/agent-verify-changes.mdc — verification obligations.
  • .cursor/rules/angular/done-is-done.mdc, .cursor/rules/angular/devil-advocate.mdc, .cursor/rules/angular/unpispas-preconditions.mdc — pre-commit quality gate for Angular/TypeScript fixes.
  • .cursor/rules/backend/done-is-done.mdc, .cursor/rules/backend/devil-advocate.mdc, .cursor/rules/phptests-bestpractices.mdc — pre-commit quality gate for PHP fixes.
  • .cursor/rules/agent-verify-changes.mdc — agent must run the validations itself.
  • .github/pull_request_template.md — PR body structure.