Fixes the two NCBI-incident-amplification bugs surfaced this cycle.
Queue wait now counts toward `totalDeadlineMs` (#50). `NcbiService.performRequest`
and `idConvert` previously constructed `runWithDeadline` inside the enqueued
task, so during NCBI eutils degradation a queued request could sit for minutes
before its deadline even started ticking. Observed `pubmed_fetch_fulltext` and
`pubmed_find_related` durations climbing in lockstep to 10+ minutes before
timing out. `runWithDeadline` now wraps the enqueue; the combined deadline +
caller signal threads into queue wait, retry backoff sleeps, and the HTTP fetch.
`NcbiRequestQueue` rewritten as a token-bucket scheduler. Two independent
ceilings: `minStartGapMs` (NCBI's per-second start-rate cap) and `maxConcurrent`
(default 8, exposed via `NCBI_MAX_CONCURRENT`, range 1–16). Decouples concurrency
from rate, so a slow upstream no longer blocks new dispatches behind a single
worker. `enqueue(task, endpoint, params, signal?)` accepts an `AbortSignal` and
rejects a still-waiting waiter immediately when its signal fires.
`pubmed_find_related` similar switches to `cmd=neighbor` with explicit
`linkname=pubmed_pubmed` (#53). NCBI's `cmd=neighbor_score` backend returned
TXCLIENT::readAll EOF for high-traffic PMIDs (1, 12345, 33567185, 37952131),
exhausting the 6-attempt retry chain. `cmd=neighbor` returns the same neighbor
list in NCBI's natural relevance order. Output schema drops the `score` field —
arbitrary-scale integer; ordering preserved without it.
Also: `devcheck` outdated-packages parser fixed for `bun outdated`'s
markdown-table format (was matching the empty leading cell as the package name).
Deps: `@cyanheads/mcp-ts-core` ^0.9.0 → ^0.9.1, `sanitize-html` ^2.17.3 →
^2.17.4, `@types/node` ^25.7.0 → ^25.8.0. `skills/api-workers/SKILL.md`
1.3 → 1.4 documents the `instructions` resolver form for Workers.
565 tests pass; bun run devcheck clean.