bd80a4d28a
Partners stop being a deployment-wide admin resource and become per-user: three nested rights (manage / use / neither) replace the blanket admin gate on the router, each member can build and own their own, and every person's conversations with a partner stay private to their account. Grants keep working and now offer only admin-managed partners. Channel runtime state moves from one directory per channel to one per partner — copied, not moved, and only when its owner is unambiguous — so two partners can finally run the same channel. Around that: a knowledge base can track GitHub repositories and re-sync their Markdown (#903); Antigravity CLI joins My Agents now that Gemini CLI is retired (#828); personal WeChat signs in from a QR code drawn in the browser instead of the server log (#951); a chat account can be linked to a DeepTutor account with /link; containers re-apply the extras they declare instead of losing them at compose down (#762); and `deeptutor doctor` answers whether a workspace is ready to run (#959). Reliability, largely from community PRs: embeddings survive a rate-limited provider through key rotation, a retry budget and a global throttle (#962); MinerU parsing and code execution work on Windows (#844, #964); indexing fails bounded instead of hanging (#946); MinerU page-layout blocks stop being indexed as content (#949); voice uploads carry a MIME the transcription API accepts (#945); and reasoning effort can be overridden per conversation (#641). Release plumbing: notes in assets/releases/ver1-5-17.md, v1.5.13 archived, __version__ 1.5.17, README Releases row and all eleven translations synced. Two defects found by the release gate and fixed here: - Six partner routes — the four channel-onboarding endpoints and both WeChat QR endpoints — kept the _auth-only mount they had inherited from the blanket admin gate, so any signed-in account could start a QR login for someone else's partner and write a bot token into its channel config. All six now declare _MANAGEABLE, and a sweep test asserts no {partner_id} route is left ungated. - A configured api_key became `str | list[str]` when key rotation landed, but ten call sites pass it somewhere that takes one key; a list would have rendered into an Authorization header verbatim. keypool.primary_api_key reduces at each boundary. Gates: pre-commit (all 15 hooks), ruff check + format, pytest 5276 passed, web 605 node tests, docs build.