Skip to content

fix(runtime): guard Truncator swap/read and un-capture stale truncator pointer (#861)#887

Merged
github-actions[bot] merged 1 commit into
mainfrom
fix/861-truncator-race
Jul 22, 2026
Merged

fix(runtime): guard Truncator swap/read and un-capture stale truncator pointer (#861)#887
github-actions[bot] merged 1 commit into
mainfrom
fix/861-truncator-race

Conversation

@Dumbris

@Dumbris Dumbris commented Jul 22, 2026

Copy link
Copy Markdown
Member

Fixes the two live defects from #861 (surfaced by Codex review of PR #857). Scope is deliberately limited to these two — the broader ApplyConfig/ReloadConfiguration side-effect unification stays tracked in #861.

Defects fixed

  1. Data race on the truncator field. Runtime.Truncator() read r.truncator without holding r.mu while the config-apply path swapped it under the lock — a real -race-detectable race. The field is now atomic.Pointer[truncate.Truncator]; the accessor Load()s and the swap Store()s. Reads stay lock-free on the serving hot path and are independent of r.mu.

  2. Stale captured truncator pointer. The MCP request handler captured the truncator pointer once at construction, so a hot-reloaded tool_response_limit never reached live tool-call responses. NewMCPProxyServer now takes a func() *truncate.Truncator getter and the serving path resolves the truncator at use time via currentTruncator(). Production passes rt.Truncator (method value), so a swap takes effect on the next call.

Composition with #857

PR #857 adds configCommitMu to serialize the config commit paths (expected to land as a configCommitMu field on internal/runtime/runtime.go). This change composes with that: the truncator swap uses an atomic.Pointer Store, independent of whichever mutex serializes the commit, and the accessor is a lock-free Load — no lock ordering to reconcile. Changes are kept minimal and localized to reduce merge-conflict risk.

Tests (TDD, failing-first)

  • TestTruncatorSwapRace (internal/runtime): concurrent Truncator() reads while ApplyConfig swaps the truncator, under -race.
  • TestTruncatorHotReloadOnServingPath (internal/server): a tool_response_limit change is observed by the serving path after reload (would fail with the old captured-pointer wiring).

Verification

  • go build ./cmd/mcpproxy and go build -tags server ./cmd/mcpproxy — pass
  • go test -race ./internal/runtime/ ./internal/server/ ./internal/truncate/ — pass
  • golangci-lint run --config .github/.golangci.yml on affected dirs — 0 issues
  • Codex cross-model sanity review (1 round) — LGTM

Refs #861 (partial — two live defects only) · follows #857

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 22, 2026

Copy link
Copy Markdown

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 41b274e
Status: ✅  Deploy successful!
Preview URL: https://6220aa89.mcpproxy-docs.pages.dev
Branch Preview URL: https://fix-861-truncator-race.mcpproxy-docs.pages.dev

View logs

@github-actions

Copy link
Copy Markdown

📦 Build Artifacts

Workflow Run: View Run
Branch: fix/861-truncator-race

Available Artifacts

  • archive-darwin-amd64 (28 MB)
  • archive-darwin-arm64 (25 MB)
  • archive-linux-amd64 (16 MB)
  • archive-linux-arm64 (15 MB)
  • archive-windows-amd64 (28 MB)
  • archive-windows-arm64 (25 MB)
  • frontend-dist-pr (0 MB)
  • installer-dmg-darwin-amd64 (22 MB)
  • installer-dmg-darwin-arm64 (20 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page linked above
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 29899225325 --repo smart-mcp-proxy/mcpproxy-go

Note: Artifacts expire in 14 days.

@github-actions github-actions Bot 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.

Approved: Codex cross-model review clean; API E2E pass at this SHA; qa-gate blessed. Arming auto-merge.

@github-actions
github-actions Bot enabled auto-merge (squash) July 22, 2026 07:51
…r pointer (#861)

Two live defects surfaced by Codex review of PR #857:

1. Data race: Runtime.Truncator() read r.truncator without holding r.mu
   while ApplyConfig swapped it under the lock (-race detectable). The
   field is now an atomic.Pointer[truncate.Truncator]; the accessor and
   the swap use Load/Store, so reads stay lock-free on the serving hot
   path and are independent of r.mu (composes with #857's configCommitMu
   commit-path serialization).

2. Stale captured pointer: the MCP request handler captured the truncator
   pointer once at construction, so a hot-reloaded tool_response_limit
   never reached live tool-call responses. NewMCPProxyServer now takes a
   func() *truncate.Truncator getter; the serving path resolves the
   truncator at use time via currentTruncator(). Production passes
   rt.Truncator (method value), so a swap takes effect on the next call.

Tests:
- TestTruncatorSwapRace: concurrent Truncator() reads + ApplyConfig swaps
  under -race.
- TestTruncatorHotReloadOnServingPath: a limit change is observed by the
  serving path after reload.

Closes #861 (partial): the two live defects only. The broader
ApplyConfig/ReloadConfiguration side-effect unification remains tracked in
@Dumbris
Dumbris force-pushed the fix/861-truncator-race branch from abf9e7b to 41b274e Compare July 22, 2026 08:54

@github-actions github-actions Bot 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.

Approved: Codex review LGTM; rebased on #888 preserving both intents; API E2E pass at this SHA. Arming auto-merge.

@github-actions
github-actions Bot merged commit 6f06b4f into main Jul 22, 2026
36 of 38 checks passed
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 78.94737% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/server/mcp.go 75.00% 2 Missing ⚠️
cmd/mcpproxy/call_cmd.go 0.00% 1 Missing ⚠️
cmd/mcpproxy/code_cmd.go 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

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