Skip to content

feat(all-mcp): bound get_contacts fan-out with optional limit (#34)#36

Open
kiki830621 wants to merge 1 commit into
mainfrom
idd/34-getcontacts-limit
Open

feat(all-mcp): bound get_contacts fan-out with optional limit (#34)#36
kiki830621 wants to merge 1 commit into
mainfrom
idd/34-getcontacts-limit

Conversation

@kiki830621

Copy link
Copy Markdown
Contributor

What

Bound get_contacts' unbounded getUser-per-id fan-out (sister to #25). getContacts looped one getUser round-trip per contact over the entire contact list with no cap.

Refs #34.

Root cause (the load-bearing difference vs #25)

TDLib's getContacts takes no args — no server-side limit, unlike getChats(limit:) / searchChats(limit:). So parseLimit on the arg would only bound the arg, not the loop. The fix truncates result.userIds client-side before the loop.

Approach (a): client-side truncation

  • get_contacts gains an optional limit (default 200, 10_000 cap via the existing tested parseLimit).
  • boundedContactIds(_ ids:limit:) in TelegramAllLib caps the fan-out; getContacts(limit: Int = 200).
  • Falsifiable seam: the fan-out itself needs a live TDLib connection (untestable in place, like [all-mcp] Apply int64ArgValueStrict to Server.swift direct callsites (sister to #22) #33), so the bound is proven by the pure boundedContactIds helper.

Rejected searchContacts (no wrapper exists; searchContacts(query:"") has uncertain typeahead semantics) and the {contacts, total} output wrap (breaks the 3 bare-array callers: handler, CLI, E2E).

Tests

5 hermetic TDLibClientContactsTests (truncate / under-limit / at-limit / empty / default-200). Mutation-verified: reverting Array(ids.prefix(limit)) to the unbounded ids turns the 2 truncation tests RED. 246 unit tests pass. CLI + E2E targets build clean with the defaulted signature.

⚠️ Behavior change (in CHANGELOG)

No-arg get_contacts callers with more than 200 contacts now get the first 200 — silently truncated. The bare-array output is kept for backward-compat (handler/CLI/E2E all consume an array), so a truncation signal would break them. Pass a higher limit (up to 10_000) for more.

Test plan

  • swift build (all products incl. telegram-all CLI) — clean
  • swift test --skip E2ETests → 246 pass
  • mutation-resistance verified (prefix → unbounded → 2 RED)
  • 6-AI verify (/idd-verify #34 --pr <N>)

🤖 Generated with Claude Code

getContacts looped one getUser per contact id over the full contact list with no
cap (sister to #25). TDLib's getContacts has no server-side limit (unlike
getChats / searchChats), so the fix truncates the id list client-side.

- get_contacts gains an optional limit (default 200, 10_000 cap via the existing
  parseLimit).
- boundedContactIds(ids:limit:) in TelegramAllLib caps the getUser-per-id loop;
  getContacts(limit: Int = 200) keeps the bare-array output so the CLI / E2E /
  MCP handler callers all compile and consume an array unchanged.
- 5 hermetic TDLibClientContactsTests; mutation-verified (reverting the prefix to
  the unbounded list turns the 2 truncation tests RED). 246 unit tests pass.

Behavior change (CHANGELOG): no-arg callers with more than 200 contacts now get
the first 200, silently truncated (the bare array is kept for backward-compat —
a truncation signal would break the 3 callers).

Refs #34
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.

1 participant