Standalone issue-close has no sanctioned path: capability resolution silently cross-switches instances, gitea_close_issue lacks worktree_path, and no mdcps reconciler route exists #711

Open
opened 2026-07-14 12:18:37 -05:00 by jcwalker3 · 1 comment
Owner

Summary

Closing a standalone Gitea issue (an issue with no PR — e.g. a duplicate) has no authorized, safe path for the mdcps (gitea.dadeschools.net) instance. A real controller-triage task (close eAgenda 913443/eAgenda#188 as a duplicate of #170) could not be completed, and the attempt exposed three compounding workflow defects plus a capability gap.

The two triage comments landed fine (they run under gitea.issue.comment, which mdcps-author has), but the terminal close could not be performed by any legitimate dadeschools profile. #188 remains open only because the supported workflow offers no authorized close path.

Reproduction (observed 2026-07-14)

  1. Active profile mdcps-author on gitea.dadeschools.net, identity 913443, repo 913443/eAgenda.
  2. Posted canonical triage comment on #170 (comment 3264) and duplicate-closure comment on #188 (comment 3273) — both succeeded under gitea.issue.comment.
  3. Called gitea_resolve_task_capability(task="close_issue", remote="dadeschools").
    • Defect A: because no mdcps profile holds gitea.issue.close, the resolver silently switched the active profile to prgs-author (identity jcwalker3, host gitea.prgs.cc) — a different Gitea instance — instead of failing closed on the requested dadeschools remote.
    • Consequence: subsequent dadeschools reads returned HTTP 404 (prgs credentials against dadeschools) until the profile was manually re-activated to mdcps-author.
  4. Called gitea_close_issue(remote="dadeschools", issue_number=188, ...).
    • Defect B: gitea_close_issue exposes no worktree_path parameter (the comment tools do), so it cannot present the session-owned branches/ worktree the guard wants.
    • Defect C: the branches-only mutation guard (#274) therefore blocks the close from the stable control checkout — there is no supported way to satisfy the guard for close_issue.
  5. Profile audit via gitea_list_profilesno dadeschools profile can close an issue:
    • mdcps-author — no gitea.issue.close
    • mdcps-reviewer — PR review ops only
    • mdcps-merger — PR merge only
    • no mdcps-reconciler exists (the prgs side has prgs-reconciler, but it only carries gitea.pr.close, not gitea.issue.close, and is the wrong instance)
    • Capability gap: only prgs-author has gitea.issue.close, on the wrong instance.

Impact

  • Standalone-issue closure (duplicates, superseded, won't-do) is unachievable on mdcps through the supported workflow.
  • Capability resolution can silently move a session across a trust/instance boundary, producing confusing 404s and a real risk of acting against the wrong instance/repo.
  • Terminal triage states are left incomplete (#188 open) despite full documentation, because there is no authorized close route.

Root causes

  1. Capability resolution treats profiles as instance-agnostic and auto-activates any profile that satisfies the requested capability, ignoring the requested remote/instance affinity.
  2. gitea_close_issue was not given the worktree_path guard-satisfaction parameter that the comment tools already have.
  3. The role/profile model has no mdcps operator/reconciler that can close a standalone issue without granting broad close permission to ordinary author sessions.

Required behavior / Acceptance criteria

  1. Strict instance & repository affinity during capability resolution. resolve_task_capability(remote=X) must only consider profiles bound to instance X; a profile for another instance is never eligible.
  2. Structured wrong-instance / missing-capability response. When the requested remote has no profile with the capability, return a structured error (requested remote, capability, reason, safe next action) — never a different-instance profile.
  3. No automatic cross-instance profile activation. Resolution must never mutate the active profile across an instance boundary as a side effect; any switch is explicit, single-instance, and operator-authorized.
  4. worktree_path support for standalone issue closure. gitea_close_issue accepts worktree_path with the same semantics as the comment tools.
  5. Branches-only guard compatibility. With a valid worktree_path, a legitimately-authorized close_issue satisfies the branches-only guard (#274) from a session-owned branches/ worktree.
  6. Dedicated mdcps reconciler/operator route for standalone issue closure. A sanctioned mdcps reconciler/operator capability can close standalone issues (with reason) without granting broad gitea.issue.close to ordinary mdcps-author sessions.
  7. Automated tests covering: wrong-instance resolution fails closed; no silent cross-instance activation; close_issue honors worktree_path; guard passes with worktree and blocks without; reconciler/operator can close a standalone issue; author cannot; success and failure paths.
  8. Audit records for every standalone close capturing identity, instance, repository, capability used, and closure reason.

Concrete follow-up needed

  • Add worktree_path to gitea_close_issue.
  • Add instance-affinity + fail-closed to gitea_resolve_task_capability (no cross-instance auto-switch).
  • Introduce a sanctioned mdcps reconciler/operator close path for standalone issues.
  • Backfill: once available, close 913443/eAgenda#188 as a duplicate of #170 (rationale already on #188 comment 3273; absorbed criteria on #170 comment 3264).

Related

  • #274 — branches-only mutation guard (the guard blocking the supported close).
  • #690 — hardening against cross-role profile activation mid-session (adjacent to the cross-instance switch here).
  • #687 — reconciler-profile capability additions (gitea.branch.delete) — precedent for adding a scoped capability to a reconciler; extend the pattern to standalone issue.close.
  • #618 — author worktree binding disappearing mid-session; mutation guards enforced inconsistently (same guard surface, worktree_path asymmetry).
  • #610 — capability resolver vs parity checks disagreement on stale runtime (resolver-behavior neighborhood).

Filed by prgs-author (jcwalker3) under a narrowly-scoped, operator-authorized switch solely to record this Gitea-Tools workflow gap. No eAgenda mutation performed under this profile; session restored to mdcps-author afterward.

## Summary Closing a **standalone Gitea issue** (an issue with no PR — e.g. a duplicate) has **no authorized, safe path** for the `mdcps` (gitea.dadeschools.net) instance. A real controller-triage task (close eAgenda `913443/eAgenda#188` as a duplicate of `#170`) could not be completed, and the attempt exposed three compounding workflow defects plus a capability gap. The two triage comments landed fine (they run under `gitea.issue.comment`, which `mdcps-author` has), but the terminal **close** could not be performed by any legitimate dadeschools profile. `#188` remains open **only** because the supported workflow offers no authorized close path. ## Reproduction (observed 2026-07-14) 1. Active profile `mdcps-author` on `gitea.dadeschools.net`, identity `913443`, repo `913443/eAgenda`. 2. Posted canonical triage comment on `#170` (comment 3264) and duplicate-closure comment on `#188` (comment 3273) — both succeeded under `gitea.issue.comment`. 3. Called `gitea_resolve_task_capability(task="close_issue", remote="dadeschools")`. - **Defect A:** because **no** `mdcps` profile holds `gitea.issue.close`, the resolver **silently switched the active profile to `prgs-author`** (identity `jcwalker3`, host **gitea.prgs.cc**) — a different Gitea instance — instead of failing closed on the requested `dadeschools` remote. - Consequence: subsequent `dadeschools` reads returned **HTTP 404** (prgs credentials against dadeschools) until the profile was manually re-activated to `mdcps-author`. 4. Called `gitea_close_issue(remote="dadeschools", issue_number=188, ...)`. - **Defect B:** `gitea_close_issue` exposes **no `worktree_path` parameter** (the comment tools do), so it cannot present the session-owned `branches/` worktree the guard wants. - **Defect C:** the **branches-only mutation guard (#274)** therefore blocks the close from the stable control checkout — there is no supported way to satisfy the guard for `close_issue`. 5. Profile audit via `gitea_list_profiles` — **no dadeschools profile can close an issue:** - `mdcps-author` — no `gitea.issue.close` - `mdcps-reviewer` — PR review ops only - `mdcps-merger` — PR merge only - no `mdcps-reconciler` exists (the `prgs` side has `prgs-reconciler`, but it only carries `gitea.pr.close`, not `gitea.issue.close`, and is the wrong instance) - **Capability gap:** only `prgs-author` has `gitea.issue.close`, on the wrong instance. ## Impact - Standalone-issue closure (duplicates, superseded, won't-do) is unachievable on `mdcps` through the supported workflow. - Capability resolution can silently move a session across a **trust/instance boundary**, producing confusing 404s and a real risk of acting against the wrong instance/repo. - Terminal triage states are left incomplete (`#188` open) despite full documentation, because there is no authorized close route. ## Root causes 1. Capability resolution treats profiles as instance-agnostic and auto-activates *any* profile that satisfies the requested capability, ignoring the requested `remote`/instance affinity. 2. `gitea_close_issue` was not given the `worktree_path` guard-satisfaction parameter that the comment tools already have. 3. The role/profile model has no `mdcps` operator/reconciler that can close a standalone issue without granting broad close permission to ordinary author sessions. ## Required behavior / Acceptance criteria 1. **Strict instance & repository affinity during capability resolution.** `resolve_task_capability(remote=X)` must only consider profiles bound to instance `X`; a profile for another instance is never eligible. 2. **Structured wrong-instance / missing-capability response.** When the requested remote has no profile with the capability, return a structured error (requested remote, capability, reason, safe next action) — never a different-instance profile. 3. **No automatic cross-instance profile activation.** Resolution must never mutate the active profile across an instance boundary as a side effect; any switch is explicit, single-instance, and operator-authorized. 4. **`worktree_path` support for standalone issue closure.** `gitea_close_issue` accepts `worktree_path` with the same semantics as the comment tools. 5. **Branches-only guard compatibility.** With a valid `worktree_path`, a legitimately-authorized `close_issue` satisfies the branches-only guard (#274) from a session-owned `branches/` worktree. 6. **Dedicated mdcps reconciler/operator route for standalone issue closure.** A sanctioned `mdcps` reconciler/operator capability can close standalone issues (with reason) **without** granting broad `gitea.issue.close` to ordinary `mdcps-author` sessions. 7. **Automated tests** covering: wrong-instance resolution fails closed; no silent cross-instance activation; `close_issue` honors `worktree_path`; guard passes with worktree and blocks without; reconciler/operator can close a standalone issue; author cannot; success and failure paths. 8. **Audit records** for every standalone close capturing identity, instance, repository, capability used, and closure reason. ## Concrete follow-up needed - Add `worktree_path` to `gitea_close_issue`. - Add instance-affinity + fail-closed to `gitea_resolve_task_capability` (no cross-instance auto-switch). - Introduce a sanctioned `mdcps` reconciler/operator close path for standalone issues. - Backfill: once available, close `913443/eAgenda#188` as a duplicate of `#170` (rationale already on `#188` comment 3273; absorbed criteria on `#170` comment 3264). ## Related - **#274** — branches-only mutation guard (the guard blocking the supported close). - **#690** — hardening against cross-role profile activation mid-session (adjacent to the cross-instance switch here). - **#687** — reconciler-profile capability additions (`gitea.branch.delete`) — precedent for adding a scoped capability to a reconciler; extend the pattern to standalone `issue.close`. - **#618** — author worktree binding disappearing mid-session; mutation guards enforced inconsistently (same guard surface, `worktree_path` asymmetry). - **#610** — capability resolver vs parity checks disagreement on stale runtime (resolver-behavior neighborhood). _Filed by prgs-author (jcwalker3) under a narrowly-scoped, operator-authorized switch solely to record this Gitea-Tools workflow gap. No eAgenda mutation performed under this profile; session restored to mdcps-author afterward._
jcwalker3 added the status:readyworkflow-hardeningsafetytype:bug labels 2026-07-14 12:18:37 -05:00
Author
Owner

Canonical Issue State

STATE: OPEN
WHO_IS_NEXT: reconciler
NEXT_ACTION: Evaluate adding MDCPS issue reconciliation profiles and capabilities
NEXT_PROMPT:

Please review Issue 711 and the added evidence for MDCPS reconciler capabilities.

WHAT_HAPPENED:
Adding evidence for MDCPS issue reconciliation capability gap:

Problem:
No stable MDCPS profile can complete canonical issue reconciliation for eAgenda.

Current gaps:

  • mdcps-author can comment/create but cannot reopen or close issues.
  • mdcps-reviewer has PR-review permissions but lacks gitea.issue.comment.
  • No mdcps reconciler/controller profile exists with controlled issue-state authority.
  • reopen_issue is unknown to the task-capability map.
  • No native reopen/edit-issue MCP tool is exposed.
  • Consequently, #170 cannot be reopened and #188 cannot receive its required canonical comment through a safe, same-host workflow.

Required design:

  • Add first-class issue reopen capability and a native MCP operation, or a constrained edit-issue operation supporting state=open.
  • Add reopen_issue to the task-capability map.
  • Provide a least-privilege MDCPS reconciliation path for:
    • issue comments;
    • reopen/close;
    • workflow-label cleanup;
    • canonical readback.
  • Prefer a dedicated mdcps-reconciler profile for issue-state mutation.
  • If reviewer issue comments are part of the intended workflow, grant only gitea.issue.comment to mdcps-reviewer; do not automatically grant broader issue administration.
  • Bind all operations to remote=dadeschools and repository=913443/eAgenda.
  • Require readback proving final issue state, comment ID, labels, identity, profile, host, and repository.
  • Never fall back to prgs profiles.

Acceptance criteria:

  1. A permitted MDCPS reconciler can reopen a closed eAgenda issue.
  2. The task resolver recognizes reopen_issue.
  3. A permitted MDCPS profile can add canonical issue comments.
  4. Reviewer permissions remain least privilege.
  5. Unauthorized profiles receive structured denial.
  6. Cross-host fallback is impossible.
  7. Tests cover reopen, comment, close, label cleanup, readback, and denial.
  8. The #170/#188 recovery scenario can complete entirely through the dadeschools profile.

Incident linkage:

  • eAgenda #170 was auto-closed by merged PR #191 despite unmet acceptance criteria.
  • eAgenda #188 remains open and must retain the unfinished scope.
  • No mutations were performed because the agent correctly failed closed.
  • Related to cross-profile drift incident reported in #714 and #712 control-plane authorization failure.

WHY: Need native issue reopen capabilities and a dedicated mdcps-reconciler to handle eAgenda issue-state mutations safely without relying on cross-host prgs profiles.
RELATED_PRS: PR #191
BLOCKERS: eAgenda Issues 170 and 188 reconciliation is blocked until an mdcps profile is granted these capabilities.
VALIDATION: Verified that existing profiles cannot reopen the eAgenda issues without falling back to a foreign host.
LAST_UPDATED_BY: Author

## Canonical Issue State STATE: OPEN WHO_IS_NEXT: reconciler NEXT_ACTION: Evaluate adding MDCPS issue reconciliation profiles and capabilities NEXT_PROMPT: ```text Please review Issue 711 and the added evidence for MDCPS reconciler capabilities. ``` WHAT_HAPPENED: Adding evidence for MDCPS issue reconciliation capability gap: Problem: No stable MDCPS profile can complete canonical issue reconciliation for eAgenda. Current gaps: - mdcps-author can comment/create but cannot reopen or close issues. - mdcps-reviewer has PR-review permissions but lacks gitea.issue.comment. - No mdcps reconciler/controller profile exists with controlled issue-state authority. - `reopen_issue` is unknown to the task-capability map. - No native reopen/edit-issue MCP tool is exposed. - Consequently, #170 cannot be reopened and #188 cannot receive its required canonical comment through a safe, same-host workflow. Required design: - Add first-class issue reopen capability and a native MCP operation, or a constrained edit-issue operation supporting state=open. - Add `reopen_issue` to the task-capability map. - Provide a least-privilege MDCPS reconciliation path for: - issue comments; - reopen/close; - workflow-label cleanup; - canonical readback. - Prefer a dedicated `mdcps-reconciler` profile for issue-state mutation. - If reviewer issue comments are part of the intended workflow, grant only `gitea.issue.comment` to mdcps-reviewer; do not automatically grant broader issue administration. - Bind all operations to remote=dadeschools and repository=913443/eAgenda. - Require readback proving final issue state, comment ID, labels, identity, profile, host, and repository. - Never fall back to prgs profiles. Acceptance criteria: 1. A permitted MDCPS reconciler can reopen a closed eAgenda issue. 2. The task resolver recognizes reopen_issue. 3. A permitted MDCPS profile can add canonical issue comments. 4. Reviewer permissions remain least privilege. 5. Unauthorized profiles receive structured denial. 6. Cross-host fallback is impossible. 7. Tests cover reopen, comment, close, label cleanup, readback, and denial. 8. The #170/#188 recovery scenario can complete entirely through the dadeschools profile. Incident linkage: - eAgenda #170 was auto-closed by merged PR #191 despite unmet acceptance criteria. - eAgenda #188 remains open and must retain the unfinished scope. - No mutations were performed because the agent correctly failed closed. - Related to cross-profile drift incident reported in #714 and #712 control-plane authorization failure. WHY: Need native issue reopen capabilities and a dedicated mdcps-reconciler to handle eAgenda issue-state mutations safely without relying on cross-host prgs profiles. RELATED_PRS: PR #191 BLOCKERS: eAgenda Issues 170 and 188 reconciliation is blocked until an mdcps profile is granted these capabilities. VALIDATION: Verified that existing profiles cannot reopen the eAgenda issues without falling back to a foreign host. LAST_UPDATED_BY: Author
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Scaled-Tech-Consulting/Gitea-Tools#711