fix(mcp): make capability resolver side-effect free (Closes #685) #724

Merged
sysadmin merged 3 commits from fix/issue-685-side-effect-free-resolver into master 2026-07-17 13:05:52 -05:00
Owner

Summary

Closes #685.

Problem

gitea_resolve_task_capability is documented as read-only, but its stale-runtime path called _trigger_mcp_auto_restart(), which:

  1. touched mcp_config.json via os.utime
  2. spawned a daemon thread that os._exit(0) after 1s
  3. closed the client transport with EOF and dropped all role namespaces mid-session

Live reproduction during this work: resolve(work_issue) returned Auto-restart has been triggered: touched mcp_config.json while master had advanced past the process boot head.

Fix

  • Remove _trigger_mcp_auto_restart entirely from the server.
  • _check_mcp_runtimes_diagnostics remains report-only: still detects self-stale / missing / all-stale profiles, never mutates config or process state.
  • Stale resolve results now include:
    • blocker_kind=runtime_reconnect_required
    • restart_required=true / stop_required=true
    • mutation_performed=false
    • precise exact_safe_next_action pointing at IDE/client reconnect (not auto-restart)
  • Docstring states the true side-effect-free contract.

Boundaries (not this PR)

Issue Scope Relationship
#685 (this) Resolver config-touch / os._exit side effects Owned here
#718 Merger lease after expiry; adopt tool internal_error Lease path only — not touched
#723 Capability map role vs profile/router disagreement Map/router invariants — not touched

Tests

  • New tests/test_issue_685_side_effect_free_resolver.py
  • Updated tests/test_mcp_stale_runtime.py

Validation

pytest tests/test_issue_685_side_effect_free_resolver.py tests/test_mcp_stale_runtime.py -q
# 11 passed

pytest tests/test_issue_685_side_effect_free_resolver.py tests/test_mcp_stale_runtime.py \
  tests/test_mcp_namespace_health.py tests/test_resolve_task_capability.py \
  tests/test_preflight_read_survival.py tests/test_reviewer_mutation_capability_proof.py -q
# 65 passed

pytest tests/ -q
# 2922 passed, 6 skipped, 1 warning, 199 subtests passed

Explicit non-goals

  • Does not weaken stale-runtime detection
  • Does not add a new restart path (#655/#657/#669)
  • Does not fix #718 lease adoption or #723 map/router invariants

Next role

Independent REVIEWER — do not self-review or merge.

## Summary Closes #685. ### Problem `gitea_resolve_task_capability` is documented as read-only, but its stale-runtime path called `_trigger_mcp_auto_restart()`, which: 1. touched `mcp_config.json` via `os.utime` 2. spawned a daemon thread that `os._exit(0)` after 1s 3. closed the client transport with EOF and dropped all role namespaces mid-session Live reproduction during this work: `resolve(work_issue)` returned `Auto-restart has been triggered: touched mcp_config.json` while master had advanced past the process boot head. ### Fix - **Remove** `_trigger_mcp_auto_restart` entirely from the server. - `_check_mcp_runtimes_diagnostics` remains **report-only**: still detects self-stale / missing / all-stale profiles, never mutates config or process state. - Stale resolve results now include: - `blocker_kind=runtime_reconnect_required` - `restart_required=true` / `stop_required=true` - `mutation_performed=false` - precise `exact_safe_next_action` pointing at **IDE/client reconnect** (not auto-restart) - Docstring states the true side-effect-free contract. ### Boundaries (not this PR) | Issue | Scope | Relationship | |-------|--------|----------------| | **#685** (this) | Resolver config-touch / `os._exit` side effects | **Owned here** | | **#718** | Merger lease after expiry; adopt tool `internal_error` | Lease path only — not touched | | **#723** | Capability map role vs profile/router disagreement | Map/router invariants — not touched | ### Tests - New `tests/test_issue_685_side_effect_free_resolver.py` - Updated `tests/test_mcp_stale_runtime.py` ### Validation ```text pytest tests/test_issue_685_side_effect_free_resolver.py tests/test_mcp_stale_runtime.py -q # 11 passed pytest tests/test_issue_685_side_effect_free_resolver.py tests/test_mcp_stale_runtime.py \ tests/test_mcp_namespace_health.py tests/test_resolve_task_capability.py \ tests/test_preflight_read_survival.py tests/test_reviewer_mutation_capability_proof.py -q # 65 passed pytest tests/ -q # 2922 passed, 6 skipped, 1 warning, 199 subtests passed ``` ### Explicit non-goals - Does not weaken stale-runtime **detection** - Does not add a new restart path (#655/#657/#669) - Does not fix #718 lease adoption or #723 map/router invariants ### Next role **Independent REVIEWER** — do not self-review or merge.
jcwalker3 added 1 commit 2026-07-16 20:23:39 -05:00
Stale-runtime detection remains fail-closed, but gitea_resolve_task_capability
must never touch mcp_config.json, spawn recovery threads, or call os._exit.

- Remove _trigger_mcp_auto_restart from the read-only diagnostics path
- Return blocker_kind=runtime_reconnect_required with mutation_performed=false
- Keep exact_safe_next_action pointing at IDE/client reconnect when stale
- Add regression suite across author/reviewer/merger/reconciler profiles
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #724
issue: #685
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 29232-d6793748490c
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-724-c780ded
phase: claimed
candidate_head: c780ded653
target_branch: master
target_branch_sha: 67e4a2b5e9
last_activity: 2026-07-17T02:01:25Z
expires_at: 2026-07-17T04:01:25Z
blocker: none

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #724 issue: #685 reviewer_identity: sysadmin profile: prgs-reviewer session_id: 29232-d6793748490c worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-724-c780ded phase: claimed candidate_head: c780ded653cba3b1f837245e4106ef9e91f33d14 target_branch: master target_branch_sha: 67e4a2b5e96b680a1dcb90a20c2ebf87357a3b1f last_activity: 2026-07-17T02:01:25Z expires_at: 2026-07-17T04:01:25Z blocker: none
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #724
issue: #685
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 389-83c75b551193
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-724-c780ded
phase: claimed
candidate_head: c780ded653
target_branch: master
target_branch_sha: 67e4a2b5e9
last_activity: 2026-07-17T13:53:58Z
expires_at: 2026-07-17T15:53:58Z
blocker: none

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #724 issue: #685 reviewer_identity: sysadmin profile: prgs-reviewer session_id: 389-83c75b551193 worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-724-c780ded phase: claimed candidate_head: c780ded653cba3b1f837245e4106ef9e91f33d14 target_branch: master target_branch_sha: 67e4a2b5e96b680a1dcb90a20c2ebf87357a3b1f last_activity: 2026-07-17T13:53:58Z expires_at: 2026-07-17T15:53:58Z blocker: none
jcwalker3 added 1 commit 2026-07-17 09:32:10 -05:00
jcwalker3 added 1 commit 2026-07-17 13:04:49 -05:00
Resolve gitea_resolve_task_capability conflict by keeping both #685
runtime_reconnect_required blocker and #702 stale_binding_recovery
annotation. Keep resolve-path stale-binding assessment report-only
(auto_recover=False) so capability resolution never mutates env or
session state. Preserve #725 merger-lease and #728 PR-sync code from
master. Regression: resolve uses report-only binding assessment.
Owner

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #724
issue: #685
reviewer_identity: sysadmin
profile: prgs-reviewer
session_id: 60168-b4fdaed96b1a
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-724-899ef8e
phase: claimed
candidate_head: 899ef8ec7f
target_branch: master
target_branch_sha: 58d6b5844f
last_activity: 2026-07-17T18:05:14Z
expires_at: 2026-07-17T20:05:14Z
blocker: none

<!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #724 issue: #685 reviewer_identity: sysadmin profile: prgs-reviewer session_id: 60168-b4fdaed96b1a worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/review-pr-724-899ef8e phase: claimed candidate_head: 899ef8ec7fde7a6e9a79d7ea7e0c9691e6b19bab target_branch: master target_branch_sha: 58d6b5844ff687888a4d94219e29bb0ea71d65e3 last_activity: 2026-07-17T18:05:14Z expires_at: 2026-07-17T20:05:14Z blocker: none
sysadmin approved these changes 2026-07-17 13:05:29 -05:00
sysadmin left a comment
Owner

Canonical PR State

STATE: approved
WHO_IS_NEXT: merger
NEXT_ACTION: Merger adopts/acquires lease and merges PR #724 at pinned head 899ef8ec7f with confirmation MERGE PR 724.
NEXT_PROMPT:

Role: MERGER (prgs-merger / sysadmin)
Repo: prgs / Scaled-Tech-Consulting / Gitea-Tools
Merge PR #724 at expected_head_sha=899ef8ec7fde7a6e9a79d7ea7e0c9691e6b19bab.
Use gitea_adopt_merger_pr_lease or gitea_acquire_merger_pr_lease, then gitea_merge_pr confirmation='MERGE PR 724'.

WHAT_HAPPENED: Independent prgs-reviewer (sysadmin) reviewed exact head 899ef8e after master merge conflict resolution. #685 removes resolver auto-restart (config touch / os._exit); stale path is report-only with blocker_kind=runtime_reconnect_required and mutation_performed=false. Resolve-path stale-binding assessment is auto_recover=False so capability resolve stays side-effect free while still annotating #702 guidance. #725 merger-lease and #728 PR-sync preserved. Focused 12 + related 204 tests passed.
WHY: Meets #685 ACs without weakening stale detection; no hidden mutations on resolve path; master features retained.
ISSUE: #685
HEAD_SHA: 899ef8ec7f
REVIEW_STATUS: approved
MERGE_READY: yes
BLOCKERS: none
VALIDATION: pytest tests/test_issue_685_side_effect_free_resolver.py tests/test_mcp_stale_runtime.py -> 12 passed; related suite 204 passed; mergeable true
NATIVE_REVIEW_PROOF: transport=native_mcp; entrypoint=mcp_server; profile=prgs-reviewer; identity=sysadmin; tool=gitea_submit_pr_review; head=899ef8ec7fde7a6e9a79d7ea7e0c9691e6b19bab; session=60168-b4fdaed96b1a
LAST_UPDATED_BY: prgs-reviewer / sysadmin

## Canonical PR State STATE: approved WHO_IS_NEXT: merger NEXT_ACTION: Merger adopts/acquires lease and merges PR #724 at pinned head 899ef8ec7fde7a6e9a79d7ea7e0c9691e6b19bab with confirmation MERGE PR 724. NEXT_PROMPT: ```text Role: MERGER (prgs-merger / sysadmin) Repo: prgs / Scaled-Tech-Consulting / Gitea-Tools Merge PR #724 at expected_head_sha=899ef8ec7fde7a6e9a79d7ea7e0c9691e6b19bab. Use gitea_adopt_merger_pr_lease or gitea_acquire_merger_pr_lease, then gitea_merge_pr confirmation='MERGE PR 724'. ``` WHAT_HAPPENED: Independent prgs-reviewer (sysadmin) reviewed exact head 899ef8e after master merge conflict resolution. #685 removes resolver auto-restart (config touch / os._exit); stale path is report-only with blocker_kind=runtime_reconnect_required and mutation_performed=false. Resolve-path stale-binding assessment is auto_recover=False so capability resolve stays side-effect free while still annotating #702 guidance. #725 merger-lease and #728 PR-sync preserved. Focused 12 + related 204 tests passed. WHY: Meets #685 ACs without weakening stale detection; no hidden mutations on resolve path; master features retained. ISSUE: #685 HEAD_SHA: 899ef8ec7fde7a6e9a79d7ea7e0c9691e6b19bab REVIEW_STATUS: approved MERGE_READY: yes BLOCKERS: none VALIDATION: pytest tests/test_issue_685_side_effect_free_resolver.py tests/test_mcp_stale_runtime.py -> 12 passed; related suite 204 passed; mergeable true NATIVE_REVIEW_PROOF: transport=native_mcp; entrypoint=mcp_server; profile=prgs-reviewer; identity=sysadmin; tool=gitea_submit_pr_review; head=899ef8ec7fde7a6e9a79d7ea7e0c9691e6b19bab; session=60168-b4fdaed96b1a LAST_UPDATED_BY: prgs-reviewer / sysadmin
Owner

adopted_at: 2026-07-17T18:05:41Z
adopted_by_identity: sysadmin
adopted_by_profile: prgs-merger
adopted_from_session_id: 60168-b4fdaed96b1a
adopted_from_profile: prgs-reviewer
adopted_from_reviewer_identity: sysadmin
adopted_from_comment_id: 12147
adoption_reason: merger-handoff-approved-head

repo: Scaled-Tech-Consulting/Gitea-Tools
pr: #724
issue: #685
reviewer_identity: sysadmin
profile: prgs-merger
session_id: 60166-1ef283925529
worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/merge-pr-724-899ef8e
phase: adopted
candidate_head: 899ef8ec7f
target_branch: master
target_branch_sha: 58d6b5844f
last_activity: 2026-07-17T18:05:41Z
expires_at: 2026-07-17T20:05:41Z
blocker: none

<!-- mcp-review-lease-adoption:v1 --> adopted_at: 2026-07-17T18:05:41Z adopted_by_identity: sysadmin adopted_by_profile: prgs-merger adopted_from_session_id: 60168-b4fdaed96b1a adopted_from_profile: prgs-reviewer adopted_from_reviewer_identity: sysadmin adopted_from_comment_id: 12147 adoption_reason: merger-handoff-approved-head <!-- mcp-review-lease:v1 --> repo: Scaled-Tech-Consulting/Gitea-Tools pr: #724 issue: #685 reviewer_identity: sysadmin profile: prgs-merger session_id: 60166-1ef283925529 worktree: /Users/jasonwalker/Development/Gitea-Tools/branches/merge-pr-724-899ef8e phase: adopted candidate_head: 899ef8ec7fde7a6e9a79d7ea7e0c9691e6b19bab target_branch: master target_branch_sha: 58d6b5844ff687888a4d94219e29bb0ea71d65e3 last_activity: 2026-07-17T18:05:41Z expires_at: 2026-07-17T20:05:41Z blocker: none
sysadmin merged commit ec2433f13b into master 2026-07-17 13:05:52 -05:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

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