Repository navigation
mcpx: Phase 1 of #2434 — structured upstream-error carriage through the gateway + local-error origin marker #2435
Copy link
Copy link
Open
Labels
app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)Package/app: mcpx (pkgs/ or apps/ in this repo)effort/mMedium: expected under 1 day of workMedium: expected under 1 day of workkind/enhancementmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)Ordinary priority (the default)source/design-architectFiled by the repo design architect jobFiled by the repo design architect jobtask/triageQueue packet kind: verify, reproduce, and route this itemQueue packet kind: verify, reproduce, and route this item
Description
Phase 1 of design #2434 (mcpx error honesty, finished). Design doc: files/designs/code-mcpx-error-honesty.md in the keep-the-four-repos-healthy goal workspace. The decisions are recorded on #2434; this phase implements its first slice.
Scope
One structured error carriage through the gateway, so a peer's error reaches the client as that peer's error, and mcpx's own errors are recognisably mcpx's:
- The daemon
/v1call reply gains a structured upstream-error field (code, message, data), populated whenever the pool/client layer holds a real JSON-RPC error from the upstream. Today the failure is flattened to text (internal/daemon/routes_proto.goToolFailurepath) andinternal/cli/serve_ask.go(~L225-255) rebuilds anUpstreamErrorby guessing at that text, with one structured special case (-32021, serve_ask.go:241). - The gateway/MCP path consumes the structured field and relays it verbatim via the existing
UpstreamErrormechanism (internal/mcpserver/capability.go). The text-reconstruction heuristics are deleted for any reply carrying the structured field; they remain only as fallback for replies that don't (older daemon / non-JSON-RPC failure). The daemon batch path's text-onlyisErrorsurfacing is in scope where it carries the same replies. - mcpx's OWN locally-minted errors (its -32602 name checks, -32603 internal failures, policy refusals) go through one minting helper that stamps
error.datawith the origin marker"mcpx": {"origin": "local"}(merged into any existing data). Peer errors are relayed untouched and never gain the marker.
Acceptance
- A pass-through upstream error and the same error via the gateway (
mcpx_call) reach the client with identical code, message and data — pinned by a parity test - An upstream -32021 relayed through the gateway keeps its
data.requiredCapabilitiesintact without the serve_ask special case - Every error mcpx mints itself on the MCP surface carries the origin marker in
data; no relayed peer error carries it - Replies without the structured field (older daemon shape) still surface as before via the text fallback
- Tests run via CI per fleet policy (no builds on the sandbox)
Out of scope: the dispatch gate (Phase 2), -32021 production (Phase 3), any change to which errors mcpx mints — only their carriage and marking.
Acceptance criteria
- Daemon
/v1call replies carry a structured upstream-error field (code, message, data) whenever the pool/client layer holds a real JSON-RPC error from upstream. - The gateway/MCP path relays that structured error verbatim via the existing
UpstreamErrormechanism; the text-reconstruction heuristics are deleted for replies carrying the field and remain only as fallback for replies without it. - Tests cover the structured relay end-to-end, the no-field fallback path, and the existing -32021 special case behaving identically through the structured path.
Metadata
Metadata
Assignees
Labels
app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)Package/app: mcpx (pkgs/ or apps/ in this repo)effort/mMedium: expected under 1 day of workMedium: expected under 1 day of workkind/enhancementmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)Ordinary priority (the default)source/design-architectFiled by the repo design architect jobFiled by the repo design architect jobtask/triageQueue packet kind: verify, reproduce, and route this itemQueue packet kind: verify, reproduce, and route this item
Activity
developing-today commentedon Oct 29, 2026
CODE-1242
dezren39 commentedon Oct 29, 2026
🤖 agent-note:v1 — design-architect pass 16 (2026-10-29). Phase 1 of design #2434. Triage packet enqueued: pilot task 3646 (queue=repo-health-code-pilot, status=queued, verified). Triage: confirm scope against current main per #2434, do not re-litigate its recorded decisions, enqueue the implementation follow-up with this issue's acceptance criteria intact.
dezren39 commentedon Oct 30, 2026
Intake review (fleet monitor, 2026-10-29 run):
/v1structured-error path since filing; main has not advanced since 10:57Z (ci: merge queue ejects every PR — no merge since #2233 (10:57Z), entries dropped 2-6 min into AWAITING_CHECKS #2403).17 remaining items
dezren39 commentedon Oct 30, 2026
🤖 Agent note · correction (queue task 3646, Lane D)
Small factual correction to the triage record: the design parent #2434 is OPEN (its title says the design is finished, which I mis-recorded as the issue being CLOSED in the fix packet evidence). The design is complete and recorded on #2434; the issue itself remains open. The triage verdict and the narrowed fix scope are unaffected.
developing-today commentedon Nov 3, 2026
agent-note:v1
state: triaged (coverage pass)
Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as triage at priority 40 (priority/normal). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
Found via: coverage pass 2026-11-03
dezren39 commentedon Nov 3, 2026
🤖 Agent note · triage verdict (task 7952)
Fresh verification at origin/main 22892c3 (2026-11-03, laptop
git grep):pkgs/mcpx/internal/cli/serve_ask.go:269still setsout.Upstream = upstreamError(errors.New(reply.Error))(text heuristic, no data); the structuredreply.Upstreamis used only for the -32021 classification at :276-279."mcpx": {"origin": "local"}marker and no minting helper anywhere underpkgs/mcpx/internal/mcpserverorpkgs/mcpx/internal/daemon./v1structured carriage (pkgs/mcpx/internal/daemon/callerr.go:109-118, populated :231) and the direct gateway relay.Queue audit (the important part): #2435's history records the implementation follow-up as enqueued twice — Lane E named "task 3957" and Lane D named a "packet-2435-fix". Neither is real: task 3957 is an unrelated #2768 triage (done), no packet-2435-fix file exists, and a dedupe-key search over the queue (2026-11-03) returns only tasks 3646 and 7952 for #2435. Phase 1 has therefore been stalled since 2026-10-30 despite two "enqueued" records — and Phase 3 (#2438) gates on it.
Routing (verified this time): narrowed small_fix enqueued as task 8625 (dedupe
repo-health:v1:fix:developing-today/code:issue:2435, packethidden_files/packets/fix-2435-narrowed-phase1.json) — serve_ask prefersreply.Upstreamwith the heuristic demoted to fallback; one minting helper stamps the origin marker on locally-minted errors only; parity + marker + fallback tests. Packet notes the cross-repo mcpx consideration (dezren39/nix vendoring) for the implementing worker.