Skip to content

Latest commit

 

History

History
102 lines (73 loc) · 5.31 KB

File metadata and controls

102 lines (73 loc) · 5.31 KB

Implementation Plan: Eliminate Remaining /api/v1/servers Refetches in macOS Tray

Branch: 048-tray-refetch-elimination | Date: 2026-05-08 | Spec: spec.md Input: specs/048-tray-refetch-elimination/spec.md

Summary

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.

Technical Context

Language/Version: Swift 5.9 (macOS 13+); Go 1.24 only for the verification harness, no Go changes in scope. Primary Dependencies: SwiftUI/AppKit (existing), Combine (existing for the periodic timer pattern). No new deps. Storage: None. Pure in-memory state. Testing: XCTest (Swift). Live reproduction harness from spec 047 (/Applications/MCPProxy.app swap-in). Target Platform: macOS 13+ (Personal edition). Project Type: Native macOS tray app subtree of the multi-target repo. 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). 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). Scale/Scope: 5 call sites across 2 Swift files (CoreProcessManager.swift, MCPProxyApp.swift). One new Combine timer.

Constitution Check

Principle Status Notes
I. Performance at Scale Reinforced Drops residual idle CPU drag from the macOS client side; complements spec 047 server-side wins.
II. Actor-Based Concurrency Aligned All refactors stay within existing MainActor / Task patterns. No new shared mutable state.
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.
IV. Security by Default No regression No auth surface change. No new permissions. No data crossing trust boundaries.
V. TDD Required One failing XCTest per site change; see tasks.md.
VI. Documentation Hygiene Aligned Spec, plan, tasks, research, quickstart, verification all committed under specs/048-tray-refetch-elimination/.

No violations. Complexity Tracking is empty.

Project Structure

Documentation (this feature)

specs/048-tray-refetch-elimination/
├── spec.md
├── plan.md                 ← this file
├── research.md             ← Phase 0
├── data-model.md           ← Phase 1
├── quickstart.md           ← Phase 1
├── tasks.md                ← Phase 2 (speckit.tasks)
└── verification/
    ├── http_log_idle.txt   ← /api/v1/servers GETs over 60 s idle
    └── report.md

(No contracts/ directory — this is a client-only refactor with no API change.)

Source Code

native/macos/MCPProxy/MCPProxy/
├── Core/CoreProcessManager.swift   ← sites 1, 2, 3 + the safety-net hook
└── MCPProxyApp.swift               ← sites 4, 5

native/macos/MCPProxy/MCPProxyTests/
└── SSEHandlerTests.swift           ← extend with 6 new tests (one per site + safety-net)

specs/048-tray-refetch-elimination/
└── verification/                   ← post-fix http.log GET counts

Structure Decision: Pure Swift refactor; the file layout above is the entirety of the change set.

Phase 0: Research (research.md)

All decisions resolved during spec drafting on 2026-05-08. Key calls captured in research.md:

  • 5-minute safety-net interval (chosen over 1 / 10 / 30 minutes).
  • Approach for refreshSecurityStatus Docker fallback (read appState.servers synchronously).
  • menuWillOpen strategy (drop refetch entirely; rely on appState).
  • How to handle "tray just opened, appState empty" race (existing initial fetch on connect covers it).

Phase 1: Design & Contracts

  • data-model.md — declares only the new safety-net timer reference held on the app-level coordinator. No persistent storage.
  • No contracts/ directory — this PR doesn't change any API.
  • quickstart.md — exact reproduction recipe for the live verification (build tray, swap into app bundle, launch, watch http.log).
  • Agent context update — runs at the end via .specify/scripts/bash/update-agent-context.sh claude.

Phase 2: Tasks (tasks.md)

Generated by /speckit.tasks from this plan. Each site change is preceded by a failing XCTest.

Risks (mirrored from spec)

See spec.md "Risks & Mitigations". No new risks identified during planning.

Out of Scope

  • Replacing refreshActivity / refreshTokenMetrics / refreshSessions periodics (separate spec; needs SSE design for those domains).
  • Investigating whether refreshSecurityStatus's Docker check could itself become SSE-driven (separate spec).
  • Adding a config key for the safety-net cadence (surface only if user feedback asks).
  • Web UI changes (already covered by spec 047).

Complexity Tracking

(empty — no Constitution gate violations)