feat(xiaohongshu): session-level velocity throttling to prevent cumulative risk-control blocks
- Dominant language
- JavaScript
- Stars
- 29.3k
- Forks
- 2.9k
- Avg merge
- 15h 36m
- Merged PRs (30d)
- 70
Description
### Context
Reading Xiaohongshu note-detail pages (`note` / `comments` / `download`) in a run trips XHS's **velocity-based** risk control — the soft block that redirects to `website-login/error?error_code=300017`/`300031` or renders `安全限制` / `访问链接异常` (#1825, #962), and repeated hammering escalates toward account-violation / ban (#842, #677).
#2207 (just opened) is the per-command half of this: it retries once through a cooldown on a soft block and never hammers. But it deliberately does **not** cap request velocity **across separate CLI invocations** — each `opencli xiaohongshu note …` is a fresh process, so a scripted loop over dozens of notes still hits detail pages back-to-back and trips the cumulative threshold. This issue is to align on the design for that second half before I build it, since it touches the daemon/session layer rather than a single adapter.
### The gap
- Per-command jitter/backoff (in #2207) makes each read gentler and recovers transient blocks.
- What's missing is a notion of *"how many detail pages have I hit recently"* that survives across invocations, plus a way to **stop** after a confirmed block instead of letting an unattended script keep hammering (which is what turns a soft block into a ban).
### Proposed shape (want your read before implementing)
The daemon is already a long-lived process holding per-context in-memory state (`SessionLeaseHolder` map in `session-lease.ts`), so it looks like the natural home for a per-site throttle:
1. **Velocity limiter** — before a `note`/`comments`/`download` navigation, consult a per-site (per-contextId) rolling window of recent detail-request timestamps; enforce a minimum spacing + a rolling-window cap (e.g. ≤ N detail reads / minute), sleeping if needed.
2. **Cooldown gate** — when any XHS detail command surfaces `SECURITY_BLOCK`, record a cooldown timestamp; detail commands within the cooldown window fail fast (`SECURITY_BLOCK` with "in cooldown until …") instead of re-hitting the hot endpoint.
### Open questions (your call on the contract)
1. **State location** — daemon in-memory (alongside the session leases) vs a small state file for non-daemon / ephemeral runs? Or in-memory only, accepting that a cold process starts with an empty window?
2. **Generic vs XHS-specific** — should this be a reusable per-site throttle other high-risk adapters can opt into, or kept inside `clis/xiaohongshu/`?
3. **Opt-in surface** — always on for XHS, or behind a flag / env (e.g. `--pace` / `OPENCLI_XHS_PACE`) so power users can tune or disable it?
4. **Default limits** — I'd start conservative (e.g. min spacing 3–6s, ≤ 12 detail reads/min, cooldown a few minutes) and make them tunable.
Happy to implement whichever shape you prefer — flagging the design first because it reaches into the daemon/session layer. Related: #2207, #1825, #962, #842, #677.
Contributor guide
Research direction
The relevant state is described as the SessionLeaseHolder map in session-lease.ts, with XHS entry points under clis/xiaohongshu/ for note, comments, and download. Start by reading those paths and #2207, then settle the state location, scope, opt-in contract, and limits; done means the design is agreed before implementation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, cli
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100