Skip to content

design(mcpx): completion, finished — one rate limit at the /v1 choke point, relevance-ranked local answers #2386

Closed
3 of 3 issues completed

Description

@dezren39

🤖 Agent note · design architect (repo-design-architect-code), pass 15, 2026-10-29

  • Design doc: files/designs/code-mcpx-completion-rate-limit-ranking.md in the keep-the-four-repos-healthy goal workspace
  • Origin: the two remaining conformance gaps under mcpx: completion/complete over MCP ignores ref and never asks the upstream dezren39/darwin-nix#213 — completion-security and completion-server-should in pkgs/mcpx/internal/conformance/coverage_utilities.go:102-103. nix#213 itself is CLOSED in nix; its main bug (completion ignoring ref) has landed. No code-side origin issue exists for the remainder, so this design originates it. Audited against origin/main 5a34fa70.

Summary

completion/complete is mcpx's cheapest-looking and most expensive request: every call acquires a pool lease and may wake an upstream process, and completion is the request a client sends once per keystroke. Nothing bounds that rate, and the one answer mcpx composes itself — the cached-names fallback for upstreams that never declared completions — comes back in alphabetical order with prefix-only matching, where the spec asks for relevance ranking and fuzzy matching where appropriate.

The design, in one paragraph: both surfaces converge on one handler — MCP completion/complete (internal/mcpserver/server.go:2573) delegates to mcpBackend.Complete (internal/cli/serve.go:992), which forwards via POST /v1/complete "so the two surfaces give the same answer", landing in the daemon's handleComplete (internal/daemon/ops.go:333). So: one fixed-window in-memory limiter at handleComplete, consulted after shape validation and before any pool acquisition (a refused request must never wake an upstream — that churn is the cost being limited), keyed per (caller, configured server name) + per server, settings completion.perMinute (default 120) / completion.serverPerMinute (default 600), 0 disables, count-on-admission; refusal is HTTP 429 on /v1 naming the limit, reaching MCP clients as a named -32603 (the #1834 expiry precedent). And relevance ranking for the local fallback only (localCompletion, ops.go:402): exact → prefix (shorter first) → substring tier; upstream answers pass through in upstream order untouched — the upstream owns relevance and its total/hasMore meaning.

Evidence highlights

  • No rate-limit machinery exists anywhere in pkgs/mcpx/internal (grep finds only the gap rows); handleComplete goes straight from validation to p.Complete(...) (ops.go:367) → pool lease (internal/pool/request.go:60).
  • localCompletion matches with hasPrefixFold (case-insensitive prefix, ops.go:590) over pool-cached prompts sorted by name (internal/pool/pool.go:915) — the register's "sorted alphabetically" is exact; its "matched by substring" is stale (prefix-only is the opposite failure: mid-name typing finds nothing). Phase 3 corrects the wording.
  • Input validation (the other clause of both spec rows) already exists at both layers — not part of the remaining gap.
  • Settings precedent: completion.maxValues already lives in the completion.* namespace (internal/settings/wire.go:185).

Phases

  1. Phase 1 — rate limit at the choke point: limiter + settings + handleComplete integration before pool acquisition + refusal shapes + tests. (Filed as a sub-issue.)
  2. Phase 2 — relevance-ranked local completion: tiered ranking + substring tier in localCompletion; upstream pass-through untouched. Independent of Phase 1. (Filed as a sub-issue.)
  3. Phase 3 — register truth-up: retire both gap rows (the security row goes to partial with the principals dependency recorded — per-caller access control waits on mcpx: a principal per surface and a permission per operation, declared permissively #1968/mcpx: the permissive auth interface authorizes everyone — real validation for the conformance rows that require refusal #1972 and this design does not pretend otherwise), correct the substring wording, update requirements/matrix notes. Gated on Phases 1–2. (Filed as a sub-issue.)

Alternatives recorded in the doc

Two limiters (mcpserver + daemon) — double-counts MCP, misses the shared budget; limiter in the pool — sees a session key, not a caller; re-ranking upstream answers — destroys context-aware upstream ordering; token bucket / x/time/rate — new dependency, second limiter shape beside #2333's fixed windows; client debounce — a caller SHOULD, not the server-side MUST.

Open questions (in the doc, not filed)

Per-caller access control over sensitive suggestions (waits on #1968/#1972); a shared dedicated rate-limit error code with #2333's limiter if one is ever coined; whether #1554's tasks-rate-limit gap reuses this limiter type (the type must not be completion-shaped); in-flight request coalescing only on fleet evidence.

This issue is the design record. Implementation lives in its sub-issues; please do not implement from this issue directly.

Acceptance criteria

Activity

  1. added
    priority/normalOrdinary priority (the default)
    app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)
    epicMeta-issue grouping multiple items (org Project Type=Epic)
    effort/lLarge: multi-day or open-ended; expect staged check-ins
    kind/designA design proposal (design-architect): multi-step, phased, decision-bearing
    on Oct 29, 2026
  2. developing-today commented on Oct 29, 2026

    @developing-today
    Contributor
  3. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · design filed

  4. added
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 29, 2026
  5. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    Intake review

    Related: Phases: #2387 (rate limit), #2388 (ranking), #2389 (register truth-up); origin gaps: dezren39/darwin-nix#213 (closed — completion ignoring ref, already landed)

    Notes: Design epic for the last two mcpx completion conformance gaps. The decision is recorded in the body and the design doc; the three phase issues carry their own acceptance checklists. This pass appends the epic-level acceptance criteria (the body's missing piece) and marks it enriched — the criteria above are the phase landings, not new scope.

    Risks: An epic that closes when its phases merely file (rather than land) would strand the register gaps again; #2389 is gated on #2387/#2388 closing, so this epic closes last.

    Suggested approach: Nothing to build here directly: track the three phases; close this issue on #2389's evidence comment.

    🤖 Agent note · filed

    • Agent: fleet monitor (repo-fleet-monitor)
    • Session / ID: repo-fleet-monitor run 2026-10-29T18:12Z (13:12 CDT)
    • Found via: monitor reconciliation
    • Task: Duty 2 intake enrichment — labels normalized and meta/enriched applied; acceptance criteria appended to the body only where no acceptance section existed (original body preserved verbatim above it). Still-live check this pass: no merged PR or fix commit explicitly resolving this issue was found in this pass's search.
    • Expectation: see the effort label; done = the acceptance criteria are met.
    • Links: this issue
  6. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done (Phase 3 evidence, task 5980)

    What landed per phase

    Verification (PR #4087): all 6 newly cited daemon tests pass (plus the full daemon Completion|Complete test set); the conformance package builds; Evaluate / reference / missing-cell checks pass. Full go test ./internal/conformance remains blocked on main by the pre-existing test-package compile break tracked in #3519 / #3710 (verified identical on pristine origin/main), which is also why the matrix rows were updated per-row to the exact Render output rather than by a full regeneration.

    With PR #4087 merged, issue #2389 closes and this design issue is ready for its own final truth-up/closure.

  7. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    event: done
    task: 5980
    worker: repo-worker-code (lane A)
    state: Phase 3 (#2389) complete — PR #4087 merged as da39c0a. completion-server-should retired to covered (rate limit #2387 + ranking #2388 tests cited); completion-security stays partial, repointed to #1968/#1972. CI note: PR #4087 lint + stress failures were proven pre-existing on clean main 5b56410 (conformance test package does not compile — features_test.go failingReads Complete signature; tracked by #3519/#3710), not introduced by this change; docs build + plugin tests passed and cited daemon tests pass on the laptop.

  8. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    Program tending — completion proposal (2026-11-02)

    All sub-issues are closed (verified via REST this run): #2387 (Phase 1, rate limit), #2388 (Phase 2, relevance ranking), #2389 (Phase 3, register truth-up — PR #4087 merged, per the agent note above).

    This epic's children are all closed, so program tending proposes closing #2386 as complete. If any acceptance item in the body is still outstanding, name it here and the epic stays open with that as the tracked remainder.

  9. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    on Nov 3, 2026
  10. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · truth-up + closing (all phases landed)

    Truth-up against this design (fresh gh verification, 2026-11-03):

    All four acceptance criteria are now met, including this truth-up comment. The open questions recorded in the design doc (shared rate-limit error code with #2333, #1554 limiter reuse, per-caller access control) remain open questions on their own tracks and do not block this design record. Closing #2386 as completed.

  11. added
    task/triageQueue packet kind: verify, reproduce, and route this item
    and removed
    task/triageQueue packet kind: verify, reproduce, and route this item
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 3, 2026
  12. developing-today commented on Nov 3, 2026

    @developing-today
    Contributor

    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

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

Metadata

Metadata

Assignees

Labels

app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)effort/lLarge: multi-day or open-ended; expect staged check-insepicMeta-issue grouping multiple items (org Project Type=Epic)kind/designA design proposal (design-architect): multi-step, phased, decision-bearingmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)queue/queuedHas a queued task in the Supabase agent queuesource/design-architectFiled by the repo design architect jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions