|
| 1 | +# Implementation Plan: Eliminate Remaining `/api/v1/servers` Refetches in macOS Tray |
| 2 | + |
| 3 | +**Branch**: `048-tray-refetch-elimination` | **Date**: 2026-05-08 | **Spec**: [`spec.md`](./spec.md) |
| 4 | +**Input**: [`specs/048-tray-refetch-elimination/spec.md`](./spec.md) |
| 5 | + |
| 6 | +## Summary |
| 7 | + |
| 8 | +Remove the 5 remaining `/api/v1/servers` refetch sites in the macOS tray. SSE-driven `appState.servers` (delivered by spec 047) is already authoritative; replace each refetch with an in-memory read or drop it entirely. Add one long-cadence (5 min) safety-net timer for missed-event resilience. Net result: tray-driven `/api/v1/servers` GETs at idle drop from ~8 / 60 s to ≤ 1 / 60 s. |
| 9 | + |
| 10 | +## Technical Context |
| 11 | + |
| 12 | +**Language/Version**: Swift 5.9 (macOS 13+); Go 1.24 only for the verification harness, no Go changes in scope. |
| 13 | +**Primary Dependencies**: SwiftUI/AppKit (existing), Combine (existing for the periodic timer pattern). No new deps. |
| 14 | +**Storage**: None. Pure in-memory state. |
| 15 | +**Testing**: XCTest (Swift). Live reproduction harness from spec 047 (`/Applications/MCPProxy.app` swap-in). |
| 16 | +**Target Platform**: macOS 13+ (Personal edition). |
| 17 | +**Project Type**: Native macOS tray app subtree of the multi-target repo. |
| 18 | +**Performance Goals**: ≤ 1 `/api/v1/servers` GET per 60 s wall at idle (down from ~8). UI reactivity unchanged (≤ 50 ms from SSE event to visible update). |
| 19 | +**Constraints**: No core / Go changes. No SSE contract change. No user-visible behavior change. Must remain backward-compatible with older cores (notify-only `servers.changed` fallback already handled by spec 047). |
| 20 | +**Scale/Scope**: 5 call sites across 2 Swift files (`CoreProcessManager.swift`, `MCPProxyApp.swift`). One new Combine timer. |
| 21 | + |
| 22 | +## Constitution Check |
| 23 | + |
| 24 | +| Principle | Status | Notes | |
| 25 | +|---|---|---| |
| 26 | +| **I. Performance at Scale** | Reinforced | Drops residual idle CPU drag from the macOS client side; complements spec 047 server-side wins. | |
| 27 | +| **II. Actor-Based Concurrency** | Aligned | All refactors stay within existing `MainActor` / `Task` patterns. No new shared mutable state. | |
| 28 | +| **III. Configuration-Driven Architecture** | Aligned | The 5-minute safety-net cadence can be hard-coded; if user feedback ever asks for tuning, surface as a config key in a follow-up. | |
| 29 | +| **IV. Security by Default** | No regression | No auth surface change. No new permissions. No data crossing trust boundaries. | |
| 30 | +| **V. TDD** | Required | One failing XCTest per site change; see `tasks.md`. | |
| 31 | +| **VI. Documentation Hygiene** | Aligned | Spec, plan, tasks, research, quickstart, verification all committed under `specs/048-tray-refetch-elimination/`. | |
| 32 | + |
| 33 | +No violations. Complexity Tracking is empty. |
| 34 | + |
| 35 | +## Project Structure |
| 36 | + |
| 37 | +### Documentation (this feature) |
| 38 | + |
| 39 | +```text |
| 40 | +specs/048-tray-refetch-elimination/ |
| 41 | +├── spec.md |
| 42 | +├── plan.md ← this file |
| 43 | +├── research.md ← Phase 0 |
| 44 | +├── data-model.md ← Phase 1 |
| 45 | +├── quickstart.md ← Phase 1 |
| 46 | +├── tasks.md ← Phase 2 (speckit.tasks) |
| 47 | +└── verification/ |
| 48 | + ├── http_log_idle.txt ← /api/v1/servers GETs over 60 s idle |
| 49 | + └── report.md |
| 50 | +``` |
| 51 | + |
| 52 | +(No `contracts/` directory — this is a client-only refactor with no API change.) |
| 53 | + |
| 54 | +### Source Code |
| 55 | + |
| 56 | +```text |
| 57 | +native/macos/MCPProxy/MCPProxy/ |
| 58 | +├── Core/CoreProcessManager.swift ← sites 1, 2, 3 + the safety-net hook |
| 59 | +└── MCPProxyApp.swift ← sites 4, 5 |
| 60 | +
|
| 61 | +native/macos/MCPProxy/MCPProxyTests/ |
| 62 | +└── SSEHandlerTests.swift ← extend with 6 new tests (one per site + safety-net) |
| 63 | +
|
| 64 | +specs/048-tray-refetch-elimination/ |
| 65 | +└── verification/ ← post-fix http.log GET counts |
| 66 | +``` |
| 67 | + |
| 68 | +**Structure Decision**: Pure Swift refactor; the file layout above is the entirety of the change set. |
| 69 | + |
| 70 | +## Phase 0: Research (`research.md`) |
| 71 | + |
| 72 | +All decisions resolved during spec drafting on 2026-05-08. Key calls captured in `research.md`: |
| 73 | +- 5-minute safety-net interval (chosen over 1 / 10 / 30 minutes). |
| 74 | +- Approach for `refreshSecurityStatus` Docker fallback (read `appState.servers` synchronously). |
| 75 | +- `menuWillOpen` strategy (drop refetch entirely; rely on appState). |
| 76 | +- How to handle "tray just opened, appState empty" race (existing initial fetch on `connect` covers it). |
| 77 | + |
| 78 | +## Phase 1: Design & Contracts |
| 79 | + |
| 80 | +- **`data-model.md`** — declares only the new safety-net timer reference held on the app-level coordinator. No persistent storage. |
| 81 | +- **No `contracts/` directory** — this PR doesn't change any API. |
| 82 | +- **`quickstart.md`** — exact reproduction recipe for the live verification (build tray, swap into app bundle, launch, watch `http.log`). |
| 83 | +- **Agent context update** — runs at the end via `.specify/scripts/bash/update-agent-context.sh claude`. |
| 84 | + |
| 85 | +## Phase 2: Tasks (`tasks.md`) |
| 86 | + |
| 87 | +Generated by `/speckit.tasks` from this plan. Each site change is preceded by a failing XCTest. |
| 88 | + |
| 89 | +## Risks (mirrored from spec) |
| 90 | + |
| 91 | +See [`spec.md`](./spec.md) "Risks & Mitigations". No new risks identified during planning. |
| 92 | + |
| 93 | +## Out of Scope |
| 94 | + |
| 95 | +- Replacing `refreshActivity` / `refreshTokenMetrics` / `refreshSessions` periodics (separate spec; needs SSE design for those domains). |
| 96 | +- Investigating whether `refreshSecurityStatus`'s Docker check could itself become SSE-driven (separate spec). |
| 97 | +- Adding a config key for the safety-net cadence (surface only if user feedback asks). |
| 98 | +- Web UI changes (already covered by spec 047). |
| 99 | + |
| 100 | +## Complexity Tracking |
| 101 | + |
| 102 | +(empty — no Constitution gate violations) |
0 commit comments