Replies: 1 comment
|
This is the sixth independent account of the same gap, and the first one to frame it as a policy question rather than a crash report — valuable. The earlier five all arrived as consumer crashes after silent removals between published versions: On your two options, the evidence says these are not accidentally-published internals — they are a real extension surface:
So the coherent answer is your option 2, and it does not require weakening the naming contract at all. "No alias, no compatibility package" governs the monorepo's own code; a removal signal is not a compatibility layer. Concretely, three levels, cheapest first:
One sibling data point argues the gates should diff shipped tags, not source: #5818 is the same root cause one layer down, where the released-session-format inventory refused two payload shapes that released writers actually emitted (permission/preset |
Uh oh!
There was an error while loading. Please reload this page.
The repository's stance on pre-stable breakage is deliberate and documented. The naming contract and rename ledger states it plainly: "No alias, compatibility package, duplicate service key, dual event name, or fallback parser remains. The repository rejects the old name."
AGENTS.mdadds: "Public APIs are pre-stable; update every consumer." As an internal policy this is coherent, and I am not arguing against it.The question is what "every consumer" means when 251 of the 260 workspace packages publish to npm as public packages. A package on a public registry acquires consumers the monorepo cannot enumerate or update. Two removals in the same week show what that costs today.
The two surfaces
UserQuestionService.registerProvider— a public, documented method: "Register the UI provider. Only one provider may be active in a context," with aDUPLICATE_PROVIDERguard and a disposer. Removed 2026-08-22 by049170c6d0(refactor(interaction): move Approval and Question into UI owners), which replaced the single active provider with the Agent-scopedctx.waterfall. Published in@deepseek-ai/dsh-user-questions@0.1.1-rc.2on 2026-08-21 12:33 UTC; absent from0.1.2-alpha.2onward.The entire ApiProxy package —
@deepseek-ai/dsh-host-apiproxy, eleven published versions from 2026-08-10 to 2026-08-21,publishConfig.access: public. Removed 2026-08-27 by4f00a8b82a(refactor(api): remove ApiProxy package).Both replacements are well-designed and properly recorded in Agent Notes — the scoped waterfall in remote event delivery, the transport takeover in session history and event transport. Internally the process worked. Neither carried a deprecation marker in the removed code, and neither note addresses an out-of-repo consumer, because the notes are not written for one.
What an external author sees
Nothing.
npm view @deepseek-ai/dsh-host-apiproxy deprecatedreturns empty — the package still resolves and installs clean, with no indication that it no longer exists upstream. There is no removal ledger to watch, no deprecation flag, and release notes do not distinguish "renamed" from "gone."The cost is already visible.
@wsz987/dsh-channelsbuilt its IM question flow onapiProxyin 0.4.2 (2026-08-21), then onregisterProviderin 0.5.0 (2026-08-24). Both paths are now orphaned — 0.4.2 by the ApiProxy removal, 0.5.0 by theregisterProviderremoval. In #5747 the author reported it after a three-layer debug session and attributed it to scoped dispatch, which is not what broke either path. That misattribution is the predictable result of having no removal signal: with nothing to consult, an author reconstructs the cause from whatever changed nearby.The question
Which of these is intended?
private, or publish only the packages meant to be built on. Twelve public packages with a stated surface is a very different promise from 251.npm deprecateon the removed name pointing at the successor is one command per removal, and a removal ledger beside the existing rename ledger would let authors track breakage without reading every merge.Either answer is workable. What is not workable is that today an author cannot tell which one applies, and finds out by having something break.
本仓库对 pre-stable 阶段破坏性变更的立场是有意为之且有文档的。命名契约与重命名台账写得很清楚:「No alias, compatibility package, duplicate service key, dual event name, or fallback parser remains. The repository rejects the old name.」
AGENTS.md另有一句:「Public APIs are pre-stable; update every consumer.」作为内部政策,这是自洽的,我并不反对它。问题在于:当 260 个 workspace 包中有 251 个以 public 身份发布到 npm 时,「every consumer」指的是谁?公共 registry 上的包会获得 monorepo 无法枚举、也无法代为更新的使用者。同一周内的两次移除,说明了当下的代价。
两个被移除的接口
UserQuestionService.registerProvider—— 一个公开且有文档的方法:「Register the UI provider. Only one provider may be active in a context.」,带DUPLICATE_PROVIDER保护和 disposer。2026-08-22 由049170c6d0(refactor(interaction): move Approval and Question into UI owners)移除,单一 provider 被换成 Agent-scopedctx.waterfall。它曾发布于@deepseek-ai/dsh-user-questions@0.1.1-rc.2(2026-08-21 12:33 UTC),自0.1.2-alpha.2起消失。整个 ApiProxy 包 ——
@deepseek-ai/dsh-host-apiproxy,2026-08-10 至 08-21 共发布 11 个版本,publishConfig.access: public。2026-08-27 由4f00a8b82a(refactor(api): remove ApiProxy package)移除。两者的替代方案都设计良好,且在 Agent Note 中有完整记录——scoped waterfall 见 remote event delivery,传输接管见 session history and event transport。就内部流程而言,一切正常。但被移除的代码里都没有 deprecation 标记,两份笔记也都没有面向仓库外的使用者——因为笔记本来就不是写给他们的。
外部作者看到的是什么
什么也看不到。
npm view @deepseek-ai/dsh-host-apiproxy deprecated返回空——这个包仍可正常解析安装,没有任何迹象表明它在上游已不复存在。没有可供关注的移除台账,没有 deprecation 标记,release notes 也不区分「改名」与「删除」。代价已经可见。
@wsz987/dsh-channels在 0.4.2(2026-08-21)把 IM 问答流程建在apiProxy上,又在 0.5.0(2026-08-24)改建在registerProvider上。两条路径如今都成了孤儿——0.4.2 死于 ApiProxy 的移除,0.5.0 死于registerProvider的移除。在 #5747 中,作者经过三层调试后提交了报告,并把原因归到 scoped dispatch 上,而那并不是任何一条路径断掉的原因。这种归因错误正是「没有移除信号」的可预期结果:无处可查时,作者只能从附近发生的变更里反推原因。问题
以下哪一种才是本意?
private,或只发布真正供人构建的那些包。12 个有明确接口说明的公开包,与 251 个,是完全不同的承诺。npm deprecate并指向后继者,每次移除只是一条命令;在现有重命名台账旁再放一份移除台账,也能让作者不必逐个阅读 merge 就能追踪破坏性变更。两种答案都可行。不可行的是现状:作者无从判断适用哪一种,只能等东西坏掉才发现。
All reactions