# ADR: Stable control runtime vs dev runtime (Gitea MCP) - **Status:** Accepted (policy effective immediately for LLM sessions; tooling may lag) - **Date:** 2026-07-09 - **Tracking issue:** [#615](https://gitea.prgs.cc/Scaled-Tech-Consulting/Gitea-Tools/issues/615) - **Related:** - [#543](https://gitea.prgs.cc/Scaled-Tech-Consulting/Gitea-Tools/issues/543) / `docs/mcp-namespace-health.md` — client-namespace health - `docs/mcp-namespace-eof-recovery.md` — reconnect-only EOF recovery (no PID kill) - [#558](https://gitea.prgs.cc/Scaled-Tech-Consulting/Gitea-Tools/issues/558) / `docs/mcp-daemon-import-guard.md` — sanctioned daemon - [#557](https://gitea.prgs.cc/Scaled-Tech-Consulting/Gitea-Tools/issues/557) / `docs/bootstrap-review-path.md` — controller bootstrap for self-hosted fixes - Allocator / control-plane ADR: `docs/architecture/mcp-allocator-control-plane-observability-adr.md` (#613 / PR #614) ## 1. Context The Gitea MCP server is the **control plane** for real issue/PR mutations (create, comment, lock, review, merge, etc.). When author/reviewer/merger/reconciler sessions kill or restart that process, relaunch it from a feature worktree, or edit the checkout that process loads, operators observe: - Mid-session identity/preflight resets - Stale-runtime vs master parity failures - IDE transport EOF / “tool not found” while code on disk has changed - Accidental production mutations from experimental code This ADR separates **stable control runtime** from **dev/test runtime** and defines promotion proof. ## 2. Decision ### 2.1 Stable control runtime The Gitea MCP server used for **real workflow mutations** is the **stable control runtime**. Characteristics: - Loads a known, promoted revision of Gitea-Tools (or the packaged release layout operators designate) - Registered in the IDE/client as the production namespaces (`gitea-tools`, `gitea-reviewer`, `gitea-merger`, `gitea-reconciler`, etc.) - Holds production profile credentials via sanctioned keychain/env paths only ### 2.2 Dev / test runtime MCP **server code** development and testing: - Happens in isolated **`branches/`** worktrees (or other non-stable checkouts) - May use a **separate** dev/test MCP runtime/process when process-level testing is required - **Must not** be used for real Gitea mutations on production issues/PRs ### 2.3 Forbidden actions (normal sessions) Normal **author, reviewer, merger, and reconciler** sessions **must not**: | Forbidden | Why | |-----------|-----| | Kill the running MCP server process | Drops all concurrent sessions; loses preflight state | | Restart the MCP server process | Same as kill; causes stale/identity churn mid-workflow | | Relaunch MCP from a development worktree | Runs unpromoted code against production mutations | | Edit files in the stable runtime checkout | Hot-mutates control plane under concurrent users | | Use experimental/dev MCP for real Gitea mutations | Bypasses promotion proof and audit expectations | EOF / transport recovery: **client reconnect only** (see `docs/mcp-namespace-eof-recovery.md`). Do not “fix” health by killing PIDs or bumping MCP config mtimes as a normal session procedure. ### 2.4 Promotion (operator / release-manager only) Promotion of a new revision into the stable control runtime is an **explicit operator/release-manager action**, not an LLM self-service step. A promotion **must record** (issue comment, release note, or promotion ledger): | Field | Description | |-------|-------------| | **previous runtime SHA** | Commit previously loaded by stable runtime | | **promoted runtime SHA** | Commit after promotion | | **source branch/PR** | Where the change was reviewed | | **restart/reload method** | How the process was cycled (e.g. supervised restart, client reload) | | **health check proof** | Client-namespace probe success (`gitea_whoami` / namespace health) | | **identity/profile proof** | Expected profile(s) and username(s) after reload | | **workspace/root proof** | Stable checkout path / root matches intended layout | | **mutation capability proof** | Required permissions for the target role present; forbidden ops still forbidden | | **rollback instructions** | How to restore previous SHA and re-verify health | Suggested durable marker: ```text ## MCP STABLE RUNTIME PROMOTION (#615) Status: COMPLETED | ROLLED_BACK | ABORTED Previous-SHA: Promoted-SHA: Source-PR: Source-Branch: Reload-Method: Health-Proof: client_namespace whoami OK / assess_mcp_namespace_health OK Identity-Proof: profile= user= Workspace-Proof: root= Mutation-Proof: allowed_ops include <…>; forbidden include <…> Rollback: checkout ; reload method <…>; re-run health/identity proofs Operator: Timestamp: ``` ### 2.5 Unhealthy stable runtime → stop work If the stable MCP runtime is **unhealthy** (client-namespace probes fail, wrong identity, wrong root, missing mutation capability, persistent EOF after reconnect): 1. **Normal PR / review / merge / issue-mutation work must stop.** 2. Do **not** improvise by switching to a dev worktree MCP for production mutations. 3. Resume only after: - runtime is restored, **or** - a **controlled** promotion/rollback completes with the promotion record above, **or** - a controller invokes the narrow **bootstrap review path** (#557) when the defect is self-hosted and documented. ## 3. Relationship to other controls | Doc / mechanism | Interaction | |-----------------|-------------| | Namespace health (#543) | Proves IDE client can call tools; does not authorize restart | | EOF recovery | Reconnect only; no process kill | | Daemon import guard (#558) | Mutations require sanctioned daemon; not a bare shell import | | Bootstrap path (#557) | Only controller-authorized exception when live runtime cannot review its own fix | | Allocator / control-plane ADR | Coordination DB is separate; still depends on a healthy MCP surface for Gitea writes | ## 4. Consequences ### Positive - Predictable control plane for concurrent LLMs - Clear operator-only promotion gate with rollback - Aligns session behavior with health/EOF docs already landed ### Costs - LLM sessions must wait when runtime is sick (no DIY restart) - Operators must maintain promotion discipline and dual-runtime config if they use a dev MCP ### Non-goals - Does not ban operator-supervised restarts during incidents - Does not replace CI or code review for MCP changes - Does not authorize editing stable checkout “because tests need a quick fix” ## 5. Implementation follow-ups (optional tooling) These may land in later issues; the **policy binds sessions now**: 1. Session preflight that refuses mutations if workspace root equals a `branches/` feature worktree configured as “dev only.” 2. Explicit `runtime_kind=stable|dev` in MCP config and `gitea_whoami` profile metadata. 3. Promotion checklist script that emits the durable promotion marker fields. 4. Operator Guide wiki cross-link to this ADR. ## 6. Acceptance for this ADR 1. Document merged under `docs/architecture/`. 2. Issue #615 references this path. 3. LLM/operator runbooks treat kill/restart/relaunch-from-worktree as **violations**. 4. Unhealthy runtime stops normal mutation work until restore/promotion/rollback/bootstrap. ## 7. Document history | Date | Change | |------|--------| | 2026-07-09 | Initial ADR: stable vs dev runtime, forbidden session actions, promotion proof fields, stop-work rule |