Skip to content

fix(gateway): close aug14 gateway ops bugs - #221

Closed
crimsonsunset wants to merge 150 commits into
mcpmux:mainfrom
crimsonsunset:docs/aug14-gateway-ops-bugs
Closed

fix(gateway): close aug14 gateway ops bugs#221
crimsonsunset wants to merge 150 commits into
mcpmux:mainfrom
crimsonsunset:docs/aug14-gateway-ops-bugs

Conversation

@crimsonsunset

@crimsonsunset crimsonsunset commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes out the Aug 14 gateway ops bugs pass: quieter logs, a cache on the hot resolve_feature_sets path, an explicit warning instead of a silent no-op when a workspace pin header shows up empty, and Unix signal attribution so a SIGTERM to the dev binary logs who sent it. Also fixes the actual cause of repeated dev-session deaths discovered while chasing that signal: Cursor's extension host reaps pnpm dev:admin when it's started from an agent shell, so that script now detaches into its own session in that case.

Changes overview

In ticket / planned scope

  • Default log level: per-crate debuginfo (RUST_LOG still overrides)
  • resolve_feature_sets: per-(space, feature_set_ids) cache, invalidated via DomainEvent::affects_mcp_capabilities(), removing a hot-path re-resolve on every tools/list
  • Present-but-empty X-Mcpmux-Workspace headers now warn! instead of silently no-oping the pin, with docs pointing at the Cursor Agents window / ${workspaceFolder} cause
  • docs/planning/aug14-gateway-ops-bugs.md: new planning doc cataloging SIGTERM attribution, session lifecycle noise, and startup hygiene, with decisions locked for this pass

Added while implementing

  • unix_signal.rs: replaces tokio::signal::unix (which drops si_pid) with a raw SA_SIGINFO handler so a SIGTERM/SIGINT log line includes the sender's pid and resolved binary path, not just "signal received"
  • Traced repeated dev-session deaths to Cursor Helper (Plugin) reaping pnpm dev:admin when it was started from an agent shell (CURSOR_AGENT=1) — scripts/dev-admin.mjs now re-execs itself detached into a new session in that case, so the agent command exits cleanly and the gateway survives extension-host teardown; dev:admin:detach added to force it from a real TTY
  • dev-stop.mjs / dev-admin.mjs: timestamped log lines on every quit/kill/signal-forward attempt, so a future death is attributable from the logs alone
  • discovery.rs: resources/list returning -32601 Method not found (servers that advertise the capability but never implement it) downgraded from warn! to debug!
  • stdio.rs: handshake failure/timeout now includes the last 10 lines of captured child stderr instead of a generic "connection closed" message
  • macos_permissions.rs: skip the Contacts requestAccess prompt under debug/tauri dev builds — TCC never persists a decision for the unsigned dev binary, so it re-prompted on every launch

Key technical decisions

  • Kept tokio::signal on the happy path elsewhere; only the one signal handler needing si_pid moved to raw sigaction, isolated in its own unix_signal.rs module
  • Cache invalidation for resolve_feature_sets is event-driven (DomainEvent), not TTL-based, so a FeatureSet edit is reflected immediately rather than after a stale window
  • Detach only triggers under CURSOR_AGENT=1 / --detach / MCPMUX_DEV_DETACH=1 — Warp/iTerm sessions stay attached so Ctrl+C still works there
  • No new supervisor/watchdog added for the detached session; a crash still stays down until pnpm dev:admin is run again, by design

Test plan

  • pnpm validate (fmt + clippy + check + eslint + typecheck) — clean at the top of this branch
  • pnpm test:rust:unit — gateway lib tests pass (255 at last full run)
  • pnpm dev:stop && pnpm dev:admin from a Cursor agent shell — confirm it prints Detached from agent (pid N) and exits, then confirm :45818/:45819/:1420 come up under a launchd-owned pid (not under Cursor Helper)
  • Trigger a SIGTERM against the dev binary and confirm the log line includes sender_pid / sender path
  • Send an empty X-Mcpmux-Workspace header and confirm a warn! instead of silent pin no-op

Docs

  • docs/planning/aug14-gateway-ops-bugs.md (new)
  • docs/manual/cursor-workspace-bridge.md, docs/planning/cursor-workspace-routing-bridge.md — updated for the empty-header decision

Autonomous decisions:
- Reverted packages/ui/src/components/layout/Sidebar.tsx and AppShell.tsx to main versions — main is ahead of i18n on these files (accent strip, hint prop, group-hover animations); porting i18n's older versions would have been a regression.
- Ported apps/desktop/src/lib/api/ shim files (app.ts, configExport.ts, settings.ts, transport.ts, oauth.ts, serverClone.ts, workspaceAppearances.ts, fetch-api.ts/helpers/types) — required by backend/shell/index.ts and build-info.helpers.ts; all are @deprecated re-export shims pointing at the new backend facade.
- In api/index.ts: selective named exports from oauth.ts instead of export * — avoids duplicate symbol conflicts with existing gateway.ts which still exports OAuthClient, RegistrationType, UpdateClientRequest, and the OAuth client CRUD functions; only oauth.ts-unique additions (flushPendingDeepLink, ConsentRequestDetails, getPendingConsent, approveOAuthConsent) are re-exported.
- Ported scripts/build-date.helpers.mjs alongside the spec'd scripts — it is a peer dependency of build-stamp.mjs and build-web-admin.mjs; omitting it would make those scripts fail at runtime.
- Updated apps/desktop/src/lib/api/index.ts to export new api shim modules — required so backend/index.ts export * from '../api' resolves all symbols the facade depends on.
…epositories

Ports the fork's storage schema onto main, renumbered 020-031 to sit after
upstream's 016-019. Extends InstalledServer (cloned_from, display_name_override,
default_params(+strategy), update_policy, pinned_version, latest_available_version,
version_checked_at, current_version), WorkspaceBinding (client_id, label), and
FeatureSetMember (surfaced) additively, with the SQLite repos round-tripping the
new columns. Adds embedding_repository + workspace_appearance_repository and their
core traits/entity.

Autonomous decisions:
- Kept main's exact-match WorkspaceBinding resolution (find_exact_for_roots); did NOT port i18n's longest-prefix + client-scope resolver — per orchestrator Choice A. client_id/label are persisted additively but stay global (None) today; per-client routing is a later gateway phase.
- Did not wire the new repos into ApplicationServices — i18n itself doesn't wire them there, and their consumers (gateway embedding/discovery services, workspace-appearance commands) land in later phases. Repos are crate-exported and unit-tested.
- Kept main's stronger InstalledServerRepository semantics (build_server -> Result, careful decrypt error distinction) rather than porting i18n's signatures; only the 9 new columns were added to the existing install/update CRUD. Did not add i18n's set_display_name_override/update_version_cache trait methods (later-phase consumers).
- Renamed migration 027's internal "-- Migration 023:" comment to 027 to match the renumbered filename.
- New feature-set members default surfaced=false at every construction site, matching migration 023's DEFAULT 0 and the entity constructors.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Port the web admin HTTP server stack from the i18n branch to main,
reconciled with Phase 1–2 divergences.

Autonomous decisions:
- Stubbed Phase 5/6/7 features (version probing, clone_server, display
  name override, public URL persistence, workspace icon upload via the
  `image` crate) with descriptive errors and ponytail comments — avoids
  pulling in unported dependencies while preserving the API surface.
- Replaced `WorkspaceBinding::new_scoped_multi` (Phase 6) with
  `new_multi` + manual client_id assignment using the existing API.
- Replaced `find_longest_prefix_match` (not yet added to the repo
  trait) with an inline prefix-scan over `list_for_space`.
- Used `option_env!` for MCPMUX_BUILD_* env vars so `cargo check`
  works outside CI without those variables set.
- Added admin settings keys and methods to `AppSettingsService` in
  mcpmux-core (get/set admin_enabled, admin_port, trust_cf_access,
  cf_team_domain) — minimal extension, no breaking changes.
- Added `space_repository()` accessor to `SpaceService` to avoid
  exposing the private `repository` field.
- Added `test-utils` feature flag to mcpmux-gateway Cargo.toml, used
  by the ported `#[cfg(feature = "test-utils")]` test helpers.
- Wired admin server startup into lib.rs setup closure; registered
  `reload_admin_server` Tauri command; integrated `emit_ui_channel`
  into the gateway domain-event bridge for SSE fan-in.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
- Add macos_dock.rs: set_dock_visible() wraps ActivationPolicy + dock visibility, cfg-gated #[cfg(target_os = "macos")] with a no-op stub for other platforms
- Add macos_permissions.rs: ensure_contacts_registered() triggers CNContactStore TCC prompt on first launch so McpMux appears in System Settings → Privacy & Security → Contacts; no-op on non-macOS
- Add main_window.rs: show_main_window() / hide_main_window_to_tray() helpers used by tray, deep-link focus, and close-to-tray handler
- Add Info.plist: NSContactsUsageDescription, NSCalendarsUsageDescription, NSRemindersUsageDescription, NSAppleEventsUsageDescription TCC keys
- Wire lib.rs: declare new modules, call ensure_contacts_registered() + set_dock_visible(false) in setup, use main_window helpers throughout
- Add commands/workspace_appearance.rs: list/upsert/delete workspace appearances + upload/resolve icon file commands
- Register workspace_appearance in commands/mod.rs and invoke_handler
- Add DomainEvent::WorkspaceAppearanceChanged to mcpmux-core and handle in gateway ui_events + desktop gateway bridge
- Add target-specific macOS Cargo deps: objc2, objc2-foundation, objc2-contacts, block2

Autonomous decisions:
- WorkspaceBinding.icon check in maybe_remove_orphaned_icon_file deferred to Phase 7 (field not yet on the entity); left a ponytail: comment
- DomainEvent::WorkspaceAppearanceChanged added now (minimal addition alongside Phase 2 entity) to unblock the commands compiling

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Port dev's split meta_tools module layout and supporting gateway
services from the i18n branch (supersedes upstream consolidated files
per plan Decision #6):

- Split meta_tools modules: invoke_*, search_tools(_index), list_servers,
  meta_tool_common, disclosure_*, feature_set_tools, bind_workspace,
  set_workspace_root, token_budget, approval_broker/types, diagnose_*.
- Gateway services: tool_discovery*, embedding, embedding_warmer,
  discovery_rank, prompt_discovery, resource_discovery.
- Wire embedding warmer into MCPNotifier on connect / feature-refresh.
- Add WorkspaceBinding::new_scoped_multi and a client-scoped-with-global
  -fallback find_longest_prefix_match default impl; use it in the admin
  effective-features bridge.
- Additive FeatureService grant helpers, ToolCallResult.structured_content,
  routing format helpers, session_roots search cache.
- Reconcile meta_tool_approval Tauri command with the always-approve broker.

package_version / server_version_probe deferred to Phase 6.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
- New Rust services: package_version, server_version_probe, server_clone
- New domain events: ServerVersionChecked, ServerUpdateAvailable
- InstalledServerRepository: set_display_name_override, update_version_cache
- ServerAppService: clone_server, is_clone_id_available, suggest_clone_suffix,
  list_clone_dependents, set_display_name_override, update_config extended
  with update_policy + pinned_version
- pool/transport/resolution: TransportResolutionOptions with update-policy
- New Tauri commands: get_build_info, set_server_display_name, clone_server,
  is_clone_id_available, suggest_clone_suffix, list_clone_dependents,
  update_server_package, get/update_server_update_settings,
  check_all_server_updates, check_server_version
- Frontend: CloneAccountModal, UninstallSourceWithClonesDialog,
  ServerActionMenu (clone + update actions), ServerUpdatesSection,
  ServerPendingUpdatesList, BuildStampPanel, StaleBuildBanner,
  use-build-stamp.hook, server-update-policy.helpers,
  server-pending-updates.helpers, server-display-name.helpers
- ServersPage: clone-aware uninstall, handleLockToCurrentVersion,
  handleUpdateNow, handleCheckForUpdate wired end-to-end
- build.rs: embed git SHA, branch, commit/build timestamps

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
- Add features/dashboard/ (DashboardPage, DashboardQuickLinks,
  DashboardRecentActivity, DashboardServerHealth, DashboardStatCards,
  dashboard.helpers, useDashboardData, index)
- Add /dashboard nav entry in navigation.ts + App.tsx route
- Port SourceBadge (add clonedFrom prop), source-badge.helpers.ts,
  AddServerMenu, ServerEnabledToggle, ServersCountSummary,
  ServersFiltersPopover, servers-page.helpers — hardcoded English
- Wire workspace appearances into WorkspacesPage (load/persist icons for
  unmapped roots, card + inspector live preview, upload via pickPath)
- Extend ServerIcon to resolve local:workspace-icons refs
- Add SpacePanel slide-out editor in features/spaces/
- Add AboutSection to features/settings/
- Add useMetaToolEvents, useOAuthClientEvents, useWorkspaceEvents shims
- Reconcile useServerManager to use useDomainEvents subscribe facade
- Add pendingServersFilter state/action/selector to appStore
- Add update_space Tauri command + SpaceService.update + updateSpace API
- Wire resolveInstalledDisplayName into registryStore.mergeServers

SpaceSwitcher already uses spaceAccentTint + space.icon (no change needed).

pnpm validate clean; no react-i18next in this phase.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Port react-i18next infrastructure and stringified UI from i18n branch
onto the reconciled Phases 1–7 port branch. Reconcile nav IA, meta-tools,
workspaces, registry analytics, and Phase 5–7 locale keys while keeping
port functionality intact.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Dashboard is the sole default nav with accent stat tiles, onboarding
strip, and live stat refresh; Home page and nav entry are removed.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Detect fork v16–27 ledger, apply upstream v16–19 SQL, and stamp v31
without re-running fork migrations that would duplicate columns.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
My Servers, Search, Bundles, Projects, and Clients labels with matching
icons; Bundles keeps a FeatureSets tooltip; e2e selectors updated.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Autonomous decisions:
- Meta-tool fixes (7e1ab44, de5ccb4, e428dcf) — no patch; dev-rebased already matches dev functionally
- Server-update probe fixes (d0d0232, 92e340f, c489692) — no patch; package_version, server_version_probe, and resolution.rs already aligned
- ServersPage / server-update-policy.helpers — no patch; shouldShowPackageUpdate already present; kept i18n getUpdatePolicyOptions over dev's hardcoded UPDATE_POLICY_OPTIONS
- write_runtime.rs — manual patch from 7414f75; wire version_probe, apply_package_update on explicit update, post-update probe to clear stale badges

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Autonomous decisions:
- Delegate openSpaceConfigFile, openUrl, addToVscode/addToCursor to shell — desktop-only commands need web-safe fallbacks without new HTTP routes
- Fix update_space route to accept flat Tauri args or nested input — Tauri IPC uses flat fields while admin REST expects a JSON body

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Wire missing admin API bridges and fetch-api routes so the web SPA can
load spaces, registry, and settings without Tauri invoke. Re-export
transport-aware domain events, enable SSE after data sync, and guard
remaining listen() call sites for admin-http mode.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Autonomous decisions:
- Run prep after backend auto-start — keeps fail-fast health check without breaking cold-start flow
- Honor MCPMUX_ADMIN_PORT in Vite proxy — matches dev script port env convention
- prep subcommand is health-check only — no port-guard utility exists in repo; Phase 1 scope is liveness

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Wire five config-export admin endpoints matching fetch-api.routes.ts:
preview, paths, check, backup, and export. Bridge logic mirrors the
existing Tauri config_export commands via ConfigExporter and enabled
server resolution through ApplicationServices.

Autonomous decisions:
- POST handlers live in handlers/write.rs; bridge logic consolidated in
  command_bridge/read.rs per plan (check/backup/export delegate there).
- Enabled servers resolved via list_for_space + filter rather than adding
  installed_server_repo to AdminBridgeCtx.
- Export always writes unmasked credentials, matching desktop Tauri behavior.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Route oauth-consent-request and oauth-client-changed through emit_ui_channel
so web admin SSE receives them, and align BuiltinServerConfigChanged SSE
mapping to builtin-server-config-changed.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Guard native openDialog/pickPath calls with isTauri() and show text path
inputs on web admin so base dirs, server config paths, and workspace
icons/roots work without crashing the browser.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Remove superseded export_config, connect_server, and disconnect_server_v2
apiCall/Tauri paths; extend admin-transport tests for builtins, config-export
routes, direct SSE channels, and dead-command guard.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Document the five-phase web admin completion work and apply rustfmt
drift from Phases 2–3 command bridge and ui_events changes.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
…ion plan

Partial Phase 1 work: list_tools uses get_advertised_tools_for_grants again.
Includes database.rs formatting cleanup and the planning doc.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Restore get_advertised_prompts_for_grants and get_advertised_resources_for_grants
in facade.rs; wire list_prompts, get_prompt, list_resources, and read_resource
to filter through surfaced feature IDs (list_tools already fixed in 93e6bef).

Autonomous decisions:
- Used get_fetchable_prompts / get_readable_resources as invokable base — matches dev branch and existing facade aliases

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Restore dev hard-cut model on call_tool, get_prompt, and read_resource:
non-surfaced invokable features redirect to meta-tool paths; inactive
tools get bind_feature_set hints via list_inactive_discovery_tools.
Re-export format_direct_* helpers from pool/mod.rs. Restore
structured_content passthrough on call_tool results.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Restore file-key credential migration at startup, WorkspaceNeedsBinding
collision_client_id alongside space_locked, and OAuth refresh dedup singleton.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Autonomous decisions:
- Marked surfacing Phases 1–3 complete with commit SHAs (126fa2f, b131a3f, 6c4d6b7)
- Audited post-port Phases 1–2 as complete (784cd41, 9747c71); Phase 3 manual QA documented
- No code fixes needed — all automated gates passed on HEAD

manual QA required: full post-port Phase 3 feature walkthrough (dashboard, i18n,
spaces, servers, feature sets, workspaces, clients, registry, builtins, settings,
meta-tools via MCP client, web admin SSE/CF Access, surfacing smoke test)

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Land label/icon metadata on workspace bindings, appearance commands,
and Projects UI ahead of machine-binding work on feat branch.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Test called the undefined render() instead of the i18n-aware helper
used elsewhere in the file, failing every run.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Autonomous decisions:
- Cap fork reconcile ledger at v32 — newer migrations must run via the normal loop, not be stamped applied during reconcile
- Preserve existing.machine_id in Tauri/admin binding update literals — compile-only ripple until Phase 3 wires machine_id through inputs

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Autonomous decisions:
- UserSpaceSyncService uses optional EventSender via with_event_sender() — keeps existing new() call sites compiling; file-watcher now wired to the app-wide EventBus sender created alongside ServerAppService
- Split regression coverage: user_space_sync event emission test + pool remove_instance unit test — full handler integration test skipped due to heavy mock surface in gateway lib tests
- Added cfg(test) insert_test_instance on PoolService — minimal test seam to assert eviction clears a pooled entry without standing up a live MCP connection
- Amended (not separate commit) — branch is ahead of origin by one unpushed Phase 3 commit; lib.rs wiring is the same logical change

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Autonomous decisions:
- Light clone-wizard touch (header-name preview, not a new form step) — Phase 1 already seeds parent extra_headers; a preview plus updated footer copy is enough visibility at create time
- Expected header keys from parent extra_headers plus required ${input:ID} HTTP definition headers — reuses existing clone/parent and registry shapes without new backend metadata
- Warn-only on enable/reconnect/refresh/retry via toast plus persistent row banner — matches Decision #3; no blocking of enable or connect

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Add planning docs for the clone auth header/config-editing fix (implemented
this session) and the custom server panel + manifest modal UI overhaul
(scoped via dig-and-ask, not yet implemented).

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Switch active-tab styling from the low-contrast accent/10 background to
primary + primary-foreground for better visibility.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
…ixes

Autonomous decisions:
- Disabled search button when editorLoadFailed — search requires Monaco; textarea fallback has no find widget
- Placed search toolbar button after Format — matches planning doc snippet order (Format then Search)

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Autonomous decisions:
- Wired Add custom server to CustomServerPanel ahead of Phase 4 — mechanical draft wiring per plan scope
- Default panel mode is JSON — Form is stub-only this phase; JSON is the working save path

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Autonomous decisions:
- Default panel mode to Form — guided creation is the primary UX now that fields exist
- Env vars stdio-only in form UI — space config http entries do not carry env at sync time
- default_params persisted in JSON entry — mirrors Configure modal field; kept out of schema-validated core fields

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Autonomous decisions:
- Plus icon for guided custom, FileJson for manifest — distinguishes panel vs full JSON editor at a glance
- Reused P2 customServerPanelSpace state — already wired; no rename to customServerPanelOpen

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Move Form/JSON toggle beside close, drop space subtitle, open Optional by default.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
…lients

Autonomous decisions:
- Reused ResolutionSource::PendingRoots for the awaiting-declaration state — matches existing prior art and keeps the enum small per planning doc decision 5
- Gate runs only when grants are non-empty — rootless sessions without grants still resolve to Unbound unchanged

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Autonomous decisions:
- Match workspace_root basenames only (not Bundle display names) — simpler query via existing list() scan
- ASCII case-insensitive basename comparison — aligns with Windows-normalized paths and tolerates cloud declare casing drift

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
… doc

Move non-component exports out of ServerDefinitionModal.tsx and
workspace-binding-form.component.tsx into dedicated helper modules so
react-refresh/only-export-components stops flagging them. Also adds
the planning doc for the declare-root-before-grant resolver gate.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Expose inbound_clients.machine_id in the Connections page (chip on
cards, picker + inline create in the side panel), make machine
selection skippable during OAuth consent, and fix the inline create
form defaulting the icon so the save button isn't stuck disabled.
Also drop the hostname autofill in that form since it misleadingly
suggested the local machine's hostname for remote connections.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Close enrichment and rank timing blind spots, and log include_inactive/scope usage so cold vs warm baselines can drive the next perf pass.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Warm path no longer full-space feature-resolves for enrichment; session index is Arc-shared and warmer embeds in one batch. Measured warm HogQL ~346ms → ~33ms.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Record Phase 1.5 hybrid keep decision, Phase 1 after numbers, and Phase 2 unlock criteria so the ticket is closed without implying FTS work next.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Surface session_id, X-Mcpmux-Workspace, pin/clobber, and resolved root so we can prove whether Agents Window shares MCP sessions across workspaces.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
A roots-capable session reporting multiple folders (no pinned
X-Mcpmux-Workspace header) was silently resolving to the first
matching binding instead of holding until unambiguous. Reuses the
existing PendingRoots pattern; mcpmux_set_workspace_root or a header
pin remains the escape hatch.

Reconciles the Agents Window spike doc with its actual finding
(session isolation works; this gate is the fix for the real bug it
surfaced) and flips the stale status on the rootless declare-root
gate doc, which already shipped Jul 23.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
mcpmux_bind_current_workspace was still first-root-wins on unpinned
multi-root sessions, so a gait agent could offer to mutate sync2hire.
Refuse until one root is pinned, list candidates in the error and in
mcpmux_list_servers PendingRoots notes, and log pre-approval binds.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
A phantom root (moved/deleted folder still reported by a stale client
source, e.g. an orphaned background-agent worker) alongside a real one
was holding sessions at PendingRoots indefinitely. If exactly one
reported root still exists on disk, narrow to it and resolve normally
instead of waiting on the client to pin a header. Genuine ambiguity —
zero or multiple surviving roots — still holds at PendingRoots.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
…am reconciliation

- New doc assesses SEP-2567/2575/2577 (sessionless MCP, handshake
  removal, roots deprecation) against mcpmux's architecture; rmcp is
  pinned at 1.5.0 so none of it is wire-visible yet, but the
  resolver's ranked-signal design already anticipates the shift.
- Upstream client-mapping reconciliation doc was stale ("Planning —
  not started") despite all 4 phases having shipped Jul 17; updated
  status and added a Resolution section with the landing commits.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
…pty workspace header

Default log level drops from per-crate debug to info (RUST_LOG still
overrides). resolve_feature_sets gets a per-(space, feature_set_ids)
cache invalidated via DomainEvent::affects_mcp_capabilities(), removing
a hot-path re-resolve on every tools/list. Present-but-empty
X-Mcpmux-Workspace headers now warn instead of silently no-oping the
pin, with docs pointing at the Cursor Agents window / ${workspaceFolder}
cause. Adds the Aug 14 gateway ops bugs planning doc cataloging the
remaining open issues (SIGTERM, session lifecycle noise, startup
hygiene) and locking decisions for the next pass.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Attribute Unix SIGTERM to the sender, orphan pnpm dev:admin from Cursor
Helper so Glass idle cannot kill the gateway, and quiet the expected
session/startup noise from the planning doc.

Signed-off-by: crimsonsunset <jsangio1@gmail.com>
Copilot AI lite review requested due to automatic review settings August 20, 2026 15:41

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

@crimsonsunset

Copy link
Copy Markdown
Contributor Author

Wrong target — recreating against crimsonsunset/mcp-mux's own main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants