dsh-xdpool 2.5.0 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,78 +1,73 @@
1
1
  # Changelog
2
2
  本项目的所有重要变更都会记录在此文件。
3
3
  版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
4
+ ## 2.5.1 — 六张 issue、一个交流群入口,外加拿掉 billion-context
4
5
 
5
- ## 2.5.0 — 十张 issue 一起收:失效账号、第三条指纹、CodeArts 上限、保存回滚、侧栏开关
6
+ > 2.5.0 之后收到的反馈集中在两类:**看得见却点不动的界面**(链不显示、单选互顶、卡片空白),和**说错话的报错**(额度已用尽、密钥无效、为预留让你调低预留)。这一版把这两类都按「根因 + 可复现断言」的方式收掉,同时按你的要求移除了 billion-context 那一页,并在「点Star」旁边加了「交流群」。
6
7
 
7
- > #68 到 #83 攒了十来张单子,其中三张(#72/#73/#74)是同一类毛病:代码把一个「没数据」和「数据是空」当成了同一件事。这批按这个线索统一收拾,另外把社区两个 PR 收了进来。
8
+ ### 修掉六张 issue
8
9
 
9
- ### 最要紧的三条
10
+ **#99 路由页有链却不显示,保存还会把链删掉**
10
11
 
11
- | 症状 | 真实原因 |
12
- | --- | --- |
13
- | 一个失效账号吃掉整次请求的 8 次重试,最后报「API 密钥无效」 | 以「刷新拿到了新 token」判定账号仍可用。有一类账号 refresh 长期有效、chat 恒回 403,判死条件因此恒假 |
14
- | buddy 某一轮被中断后,之后每一轮都失败(`a message has empty content`) | 中断留下的 assistant 消息只有 reasoning、没有正文,序列化时空字符串被原样发到 wire,国内网关 400/11151 且不在重试集合里 |
15
- | zcode 全部模型勾选后,每次重启又变回全禁用 | 用户全开时黑名单是空对象,与「从未选过」无法区分,启动补静音据此又把它们全关一遍 |
16
-
17
- ### #68 失效账号耗尽重试预算
18
-
19
- 池车道以「刷新成功」当「账号可用」。对 refresh 长期有效而业务侧恒 403 的账号,`recovered` 与 `accessToken !== before` 恒真 ⇒ 永不 `penalizeCredentialDead` ⇒ `available()` 不排除 ⇒ `priority` 下 `acquire()` 一直返回同一个 ⇒ 8 次预算全花在它身上。
20
-
21
- 改法:单次请求内只允许该账号换一次票(`refreshedThisRequest`),第二次仍报 `session_dead` 就直接判死并轮到下一个账号。压缩重试路径同步。取「第二次」而不是把惩罚提到刷新之前,是为了仍给真正过期的 token 一次机会。
22
-
23
- ### #70 侧栏入口开关
24
-
25
- 新增 `sidebarRow` 配置(默认开)。**只**控制左侧栏那一行:设置页的 XD Pool 卡片始终注册,模型池不受影响 —— 关掉入口不能把开关本身也锁在门外。开关写在卡片里,`apply()` 与卡片读同一份设置镜像,因此两边不会给出不同答案;宿主发布了变更通知的平台上无需重启。
12
+ `setDrafts(prev => seeded.current ? prev : …)` 把守卫放进了函数式更新回调,紧接着一行同步 `seeded.current = true`。React 的回调在提交阶段才跑,那时标志位已经是 `true`,于是恒走 `prev` 分支 —— 初始值 `[]` 原样返回。列表恒空,而保存提交的是整张表,**第一次保存就把服务端那条链覆盖成空**。
26
13
 
27
- ### #72 订阅包余额虚高 30 倍
14
+ 改成同步判断再置位(与同项目 `GatewayPage.tsx` 同形)。回归用例现在连「形状」一起锁:不许再出现 `setDrafts(prev => seeded …)`。
28
15
 
29
- `fetchCredits` 只把 `CapacityType === 4` 当月包,而实际有三种:`1`=一次性包、`2`=**周期订阅包**(12 期 × 4000,`CapacityRemain` 是整期剩余、`CycleCapacityRemain` 才是当期剩余)、`4`=月包。`type=2` 落进「一次性」分支,整期额度被当余额。三账号实测:官方 3,399.8 / 插件 102,396 → 修复后 3,366;另两个只有月包的账号(3,049 / 2,771)不变,所以长期没被发现。
16
+ **#101 国内版/国际版的「1M」互相顶掉**
30
17
 
31
- `expiresAtMs` 对 `type=2` 取 `DeductionEndTime`,**不能用 `CycleEndTime`** —— 它每月都到,会让「会过期」天天报警。空包只在一次性包时丢弃,月包当期耗尽要留着显示「0/500 · 下月回满」。
18
+ 两张区域卡同时挂载(折叠面板用 `hidden`,不是卸载),预算单选 `name` 只用了 `budget-${model.id}`,同名即同组,浏览器只保留最后一个 `checked`。后渲染的国际版把国内版的黑点顶掉,表现为「点了没保存」。用 `useId()` 给每一行实例加作用域 —— 只加 region 不够,设置页与侧栏可能同时挂载同一区域。
32
19
 
33
- Refs #72。
20
+ **#102 切回账号池就重拉全部数据(2–4 秒空白)**
34
21
 
35
- ### #73 中断回合留下的空 assistant 消息
22
+ 页签正文是三选一表达式,切页即卸载,`useState` 随之清零;而且 `load()` 把 `account.list` / `model.list` / `credits.balances` / `credits.status` 四合一一 `await Promise.all`,让整张卡等唯一走网络的余额查询。
36
23
 
37
- `serializeMessages2` 出口加 `isBlankWireMessage` / `dropBlankWireMessages`,`serializeMessages4` 同步。三点取舍都用真实请求验证过:`user` 空消息不动(两网关都容忍);不伪造占位内容(会污染模型看到的对话);**有 `tool_calls` 的 assistant 消息绝不删**(它是 tool 结果的配对锚点,删了造孤儿)。
24
+ - 快照提到模块作用域,且**写在 `mountedRef` 判据之前**:已经发出去的结果即便在卸载后才回来,仍然落进快照
25
+ - 拆两波:wave1 只问内存里的三项,先把卡画全(余额格写 `…`);wave2 每渠道各自回填
26
+ - `balancePending` 原来被硬编成 `false`,让渲染层那条 `…` 分支成了死代码 —— 现在真正用上了
27
+ - 每次加载带单调序号,旧答案盖不掉新答案
38
28
 
39
- 实测矩阵(国内):空 assistant 400/11151;空 system 同样 400/11151;空 user 200;`content:null` + `tool_calls` 200;删掉空 assistant 后正常 SSE。国际网关对全部形态都 200,所以故障面目前只在 buddy 车道。
29
+ **#95 扫码渠道卡整片空白,且不报错**
40
30
 
41
- Refs #73。
31
+ `if (entries.length === 0 && error === undefined) return <></>`。而 RPC 桥解析失败时 `provider.status` 回 `ok: false`、映射出空 map、`entries` 为空、`error` 仍是 `undefined` —— **「桥断了」和「没有扫码账号」渲染成同一片空气**。
42
32
 
43
- ### #74 全开渠道每次重启被重新禁用
33
+ 改成三态:读取中一行字、失败写明原因、成功但确实没有账号才保持安静。
44
34
 
45
- `setModelDisabled` 打开模型时是**删键**而不是写 `false`,于是「用户全开」与「从未选择」在磁盘上是同一个空对象。新增持久标记 `selectionTouched`:四个用户入口(`setModelDisabled` / `setModelsDisabled` / `clearModelsDisabled` / `clearDisabledModels`)都置位,启动补静音只在标记缺失时执行,且自身写黑名单时传 `{ mark: false }` 不置位。
35
+ **#98 自动化三处**
46
36
 
47
- 影响面是「所有模型都打开」的渠道,目录越小越必然(zcode 2 个、gemini/minimax/raccoon 同理);部分启用的渠道免疫,这解释了为什么只有 zcode 反复被报。
37
+ - 「体验XX专家」任务族(`expert_use_maidehao` / `douyinyin` / `shangjia_xuanchuan` / `bowangwang`,加同族的 `WorkBuddy_Valorant`)不在 `EVENT_CHAIN_BUILDERS` 里,所以 accept 和 claim 都正常、进度永远 0/1。这批专家**不在市场列表里**,expertId 只存在于任务自己的 `jump_url` 里(percent-encoded deeplink),因此新增 `expertIdFromJumpUrl()`:先解 `deeplink` 参数、再读内层 `expertId`。use 事件保持默认 `craft` 模式 —— `LOCAL`/零成本是 lighthouse 的专属判据。
38
+ - `unavailableReason()` 遇到第一个低于预留的账号就 `return reserve`,后面账号根本没检查。一张 5 账号池里只要有一个长期低于预留线,任何失败都会被归因成 402「调低预留」。改为计数式:`dead`/`cooling`/`disabled` 先报(这些改数字改不好),只有**无可用账号且全部被预留挡住**才报 `reserve`。
39
+ - `automationEarnings` 写入是 fire-and-forget,领取完成到进程退出的窗口里丢账(实测领了 21 个任务,落盘仍是 `credit: 0`)。`persistEarnings()` 改为返回 promise,`runJob` 收尾 `await this.flushEarnings()`。
48
40
 
49
- Refs #74。
41
+ **#96 免密 lane 全失败,却报「额度已用尽」**
50
42
 
51
- ### #75 保存模型选择后界面回滚 30 秒
43
+ 403 指纹拒绝被渲染成宿主自己的措辞,指向「等待」;真正该做的是「升级插件」。新增 `withFreeTierHint()`:先说指纹失配、明确「等待无用,请更新」,再保留 per-conversation 配额这一可能(两者从外部无法区分,不自作聪明)。429 仍走原有的会话配额提示。
52
44
 
53
- `saveModels` 收尾是 `setDraftFor(region, undefined)`,而它的语义是「退回池子最后报告的状态」,那份状态靠 30 秒轮询刷新 —— 于是保存后卡片画的是**保存前**的清单,用户在这 30 秒里再点一次保存,写入的就是回滚后的旧清单。另外 `settingsScope.set` 被声明成 `Promise<void>`,把宿主 revision 冲突时返回的 `false` 丢掉了,被拒绝也提示「已保存」。
45
+ ### 新增:「交流群」
54
46
 
55
- 改法:先 `refresh(region)` 再清草稿(重读失败则保留草稿);`set` 返回类型放宽到 `boolean | void`,`=== false` 时保留草稿、报「设置已在别处被修改」、不显示已保存。
47
+ - 卡片右上角「点Star」旁边多一个「交流群」按钮,点开在原位弹层显示微信群码
48
+ - 底部导航网格从 `1fr auto` 扩成 `1fr auto auto`,否则第二个按钮会掉到标签栏下面
49
+ - 二维码以 data URI 内嵌进 `lib/client.js`:客户端是宿主加载的单个脚本,解析不了包内相对路径,而 `<img>` 加载失败是**静默**的
50
+ - Esc 与点击遮罩都能关;`alt` 写的是操作指引(读屏用户扫不了码)
51
+ - 同一张图放在 `README.md` 与 `README.en.md` 第 13 行(标题与徽章之后),过期了换 `assets/community-qr.png` 并重跑 `tools/make-community-qr.mjs`
56
52
 
57
- Refs #75。
53
+ ### 移除:billion-context
58
54
 
59
- ### #82 RPC 桥惰性解析
55
+ 那一页只读观测另一个插件的回环代理。连同 `src/billion.ts`、`src/billion-mount.ts`、`src/client/BillionPage.tsx`、`/plugins/dsh-xdpool/billion` 路由、`POOL_BILLION_PATH` 与两个文档类型、84 个 `billion.*`/`shell.tabBillion` 语言键、`BILLION_CARD_CSS`、`optionalDependencies.billion-context`,以及 `cordis.patch.yml` 里那行长期 `disabled: true` 的条目一起删掉。README 的页面表随之从七页改回六页。
60
56
 
61
- 2.4.6 的 CHANGELOG 声称这条已修,但发布产物里 `installPackRpc` 仍只捕获一次。现已改为每次 `callPack` 前 `if (packRpcBridge === undefined) packRpcBridge = resolvePackRpcBridge()`:`connection` 就绪晚于 `apply()` 时,桥不会再永久为空、退化成裸 `fetch('/api/channel-pack')` 吃 401 而让账号池整片空白。
57
+ ### 一并发布的两个既有改动
62
58
 
63
- Refs #82。
59
+ - **CodeArts 的输出上限是上限,不是默认值** —— `listModels()` 报 `maxTokens`、`resolveModel()` 报 `defaultMaxTokens`、线上 `max_tokens` 做 `Math.min` clamp。原先 `?? 65536` 只兜底不设界,宿主把别的 provider 的 384000 原样递过来就触发 HTTP-200 的 SSE 错误帧。见 #83 / #69。
60
+ - **第三条内容指纹** —— 「Relative paths resolve from the workspace root」改成过去分词形式,池车道与渠道车道同步。见 #77 / #79。
64
61
 
65
- ### 同批合并的社区 PR
66
-
67
- - **#81([@jmglsi](https://github.com/jmglsi))** 第三条内容指纹:`Relative paths resolve from the workspace root` → `are resolved against the workspace root`。用陈述句的过去分词形式,语义、长度、换行位置都不变,被网关字符串表收录的子串消失。
68
- - **#84([@Refeain](https://github.com/Refeain))** CodeArts 输出上限见下节。
62
+ ### 验证
69
63
 
70
- ### #69 / #71 尚未定性
64
+ - 全套 **83 文件 1057 用例全绿**;host 侧 `tsc --noEmit` 干净
65
+ - 新增 6 个测试文件:`billion-removed` / `card-shell`(交流群)/ `channel-pool-loading` / `expert-task-family` / `free-lane-refusal` / `reserve-floor-scope`
66
+ - 交互验证不只做源码断言:`tools/probe-card-render.mjs` 用最小 hook 调度器驱动真实 `PoolShell`,完成「点击 → 重渲染 → 弹层出现 → 二维码 8666 字符 data URI → 遮罩关闭」整条链路
71
67
 
72
- `#69 CodeArts 提示密钥无效` 只有一句话。它至少有两条来源:本条 `InferHub.4001.200`(SSE 帧里的 200,不是 4xx)与真正的 401/403。前者已随 #83 修掉;后者需要失败时的原始响应才能确认。
73
- `#71 kimi k3.1 pro 没有响应` 同样只有一句话,且目录里没有 `kimi-k3.1-pro` 这个 id(有 `kimi-k3-1`)。请在 issue 里补一下:是空回复、卡住不动、还是有报错文案。
68
+ Refs #95 #96 #98 #99 #101 #102。
74
69
 
75
- ### 详情:CodeArts 的输出上限是上限,不是默认值
70
+ ## 附:CodeArts 的输出上限是上限,不是默认值(细节,已并入 2.5.1)
76
71
 
77
72
  > 华为这条链接 65536 能用、131072 就空流,代码里也一直写着这个数字。但它是 `options.maxTokens ?? 65536` —— 只兜底,不设界。
78
73
 
@@ -109,7 +104,7 @@ TRAE 与 Cline 早就这么做了(`clampTraeMaxTokens` / `clampClineMaxTokens`
109
104
 
110
105
  Refs #83, #69。
111
106
 
112
- ### 详情:第三条内容指纹:文件引用指引里的 “resolve from the workspace root”
107
+ ## 附:第三条内容指纹 —— 文件引用指引里的 “resolve from the workspace root”(细节,已并入 2.5.1)
113
108
 
114
109
  > 2.4.1/2.4.2 修好的两个指纹管了一周,10 月 28 日又整片 400/11128。这次被点名的不是产品名,而是一句普通说明。
115
110
 
@@ -130,12 +125,6 @@ DSH 在 agent 有 `read` 工具时会贡献一段文件引用指引,开头是
130
125
  ### 其他
131
126
  - 全套 79 文件 1028 用例(1026 通过 + 2 跳过)。
132
127
 
133
- ### 验证
134
-
135
- - 全套 **80 文件 / 1033 用例**(含 #81 的 5 例、#84 的 5 例、本批新增)
136
- - `pack.js` 每次改动后 `node --check` 通过
137
- - server `tsc` 0 错;client `tsc` 的 6 条是既存问题(`accounts.ts` / `context-budget.ts` / `free-upstream.ts` 的 Node 类型不匹配),改前改后数量一致
138
-
139
128
  ## 2.4.6 — 扫码账号每次打开都空白:一份数据卡在两个细节里
140
129
 
141
130
  > 2.4.4/2.4.5 之后侧栏能进、能滚了,但扫码过的渠道在账号池里经常整片空白,重开也一样。磁盘上账号是齐的(`state.json` 里 15 条),所以问题全在读取链。
package/README.en.md CHANGED
@@ -7,6 +7,16 @@
7
7
  <a href="https://github.com/XDTrees/dsh-xdpool/stargazers"><img src="https://img.shields.io/github/stars/XDTrees/dsh-xdpool?style=flat-square" alt="GitHub stars"></a>
8
8
  </p>
9
9
 
10
+ ## Join the group
11
+
12
+ <p align="center">
13
+ <img src="assets/community-qr.png" width="300" alt="WeChat group code: XD community group">
14
+ <br>
15
+ <sub>Scan with WeChat to join the <b>XD community group</b>. The code is valid for 7 days; if it has expired, say so in <a href="https://github.com/XDTrees/dsh-xdpool/issues">issues</a> and it will be refreshed.</sub>
16
+ <br>
17
+ <sub>The 交流群 button next to “Star” in the card's top-right corner opens this same code — no need to come back to the README.</sub>
18
+ </p>
19
+
10
20
  <p align="center">
11
21
  <sub>Download stats still come from the previous package name <code>dsh-workbuddy-xdpool</code> (8,976/month as of 2026-10-12 — every download before the rename; the live shields badge kept getting rate-limited by the npm upstream, hence the snapshot figure). The new <code>dsh-xdpool</code> package accumulates its own stats, and the badge switches back to live data later.</sub>
12
22
  </p>
@@ -17,7 +27,7 @@ English | [中文](./README.md)
17
27
 
18
28
  It started as one thing: every account you've signed into the WorkBuddy desktop app, merged into one auto-failing-over pool. An account gets rate-limited or runs out of credits, and the request moves to the next one that works. No picking favourites, no manual import.
19
29
 
20
- Then it grew into seven pages. Beyond the account pool: sign in to thirteen vendors' free models by web or QR, aggregate **76 vendors'** free quotas into one lane, read a usage ledger, chain models together, and expose the pool as a local OpenAI-compatible gateway.
30
+ Then it grew into six pages. Beyond the account pool: sign in to thirteen vendors' free models by web or QR, aggregate **76 vendors'** free quotas into one lane, read a usage ledger, chain models together, and expose the pool as a local OpenAI-compatible gateway.
21
31
 
22
32
  | Page | What it does |
23
33
  | --- | --- |
@@ -25,7 +35,6 @@ Then it grew into seven pages. Beyond the account pool: sign in to thirteen vend
25
35
  | **Login channels** | Thirteen vendors that sign in by web or QR — once, and their free models join the picker |
26
36
  | **Aggregate** | 76 vendors' free quotas into one pool (none on by default; a vendor lights up when it has a key) |
27
37
  | **Dashboard** | Today's turns, calls, failures, failover rescues, tokens, cache hits, speed |
28
- | **billion-context** | Read-only view of the local billion-context compressor |
29
38
  | **Routing** | Chain several models, in order or round-robin |
30
39
  | **Gateway** | Expose the pool as a local OpenAI-compatible endpoint, optionally to your LAN |
31
40
 
package/README.md CHANGED
@@ -7,6 +7,16 @@
7
7
  <a href="https://github.com/XDTrees/dsh-xdpool/stargazers"><img src="https://img.shields.io/github/stars/XDTrees/dsh-xdpool?style=flat-square" alt="GitHub stars"></a>
8
8
  </p>
9
9
 
10
+ ## 先加群
11
+
12
+ <p align="center">
13
+ <img src="assets/community-qr.png" width="300" alt="微信群二维码:XD 交流群">
14
+ <br>
15
+ <sub>微信扫一扫加入 <b>XD 交流群</b>。二维码 7 天内有效;过期了在 <a href="https://github.com/XDTrees/dsh-xdpool/issues">issues</a> 说一声会换新。</sub>
16
+ <br>
17
+ <sub>卡片右上角「点Star」旁边的「交流群」按钮打开的也是这个码 —— 不用回头找 README。</sub>
18
+ </p>
19
+
10
20
  <p align="center">
11
21
  <sub>下载量统计沿用旧包名 <code>dsh-workbuddy-xdpool</code>(截至 2026-10-12 为 8,976 次/月,改名前的全部下载;shields 的实时徽章常被 npm 上游限流,所以这里用了快照数字)。新包 <code>dsh-xdpool</code> 的统计会随时间累积,之后徽章会换回实时数据。</sub>
12
22
  </p>
@@ -17,7 +27,7 @@
17
27
 
18
28
  它从一件事开始——把本机 WorkBuddy 桌面 App 里登录过的**所有账号**合成一个自动容错的池子,哪个号被限流了、积分用光了,请求自动换到下一个能用的号上去。你不用挑号,不用手动导入。
19
29
 
20
- 然后它长成了七页:账号池之外,还能扫码登录十三家厂商的免费模型、把 **76 家**厂商的免费额度聚合成一条通道、看用量账本、把几个模型串成链、把池子开成一个本地 OpenAI 兼容网关。
30
+ 然后它长成了六页:账号池之外,还能扫码登录十三家厂商的免费模型、把 **76 家**厂商的免费额度聚合成一条通道、看用量账本、把几个模型串成链、把池子开成一个本地 OpenAI 兼容网关。
21
31
 
22
32
  | 页面 | 干什么 |
23
33
  | --- | --- |
@@ -25,7 +35,6 @@
25
35
  | **扫码登录** | 十三家支持网页 / 扫码登录的厂商,登一次,它们的免费模型就进选择器 |
26
36
  | **聚合渠道** | 76 家厂商的免费额度接进同一个池(默认一家都不开,填了 key 才亮) |
27
37
  | **数据看板** | 今天的轮次、调用、失败、换号救回、token、缓存命中、速度 |
28
- | **billion-context** | 只读观测本机 billion-context 压缩器的运行状态 |
29
38
  | **路由** | 把多个模型串成一条链,按顺序或轮换使用 |
30
39
  | **网关** | 把池子开成本地 OpenAI 兼容接口,可转发给局域网其它设备 |
31
40
 
@@ -38,7 +47,7 @@
38
47
 
39
48
  ## 先看几张图
40
49
 
41
- **账号池(卡片首页:品牌栏 + 七个页面标签,顶部就是用量)**
50
+ **账号池(卡片首页:品牌栏 + 六个页面标签,顶部就是用量)**
42
51
 
43
52
  ![账号池:顶栏显示 XD Pool 与版本号、七个页面标签、用量面板在页面最上方、下方是 WorkBuddy 国内版账号卡与「已接入」状态](assets/account-pool.png)
44
53
 
Binary file
package/cordis.patch.yml CHANGED
@@ -4,45 +4,21 @@
4
4
  - insert:
5
5
  - id: llm-xdpool
6
6
  name: dsh-xdpool
7
- # billion-context is deliberately NOT mounted by this layer.
8
7
  #
9
- # 2.0.0 tried to. It inserted a row (`billion-context-xdpool`) so a profile that
10
- # had not installed the compressor would get one for free, and `src/billion-mount.ts`
11
- # held a runtime `create()` as a second path for the same job. Measured against a
12
- # profile that had ALREADY installed billion-context — which is the normal state
13
- # for anyone using that feature, since `bili-native` comes from billion-context's
14
- # own `dsh.bundle.patch.yml` — neither safeguard held:
15
- #
16
- # the host did not disable our duplicate row, and it did not resolve it to a
17
- # no-op. It left `enabled: true` and ran the fiber to `failed`, because
18
- # billion-context registers a cordis service under its own name and a second
19
- # registration is refused outright (`service "…" has been registered at <…>`).
20
- #
21
- # So every user who had installed billion-context got a permanently failed entry
22
- # in their plugin list — visible, unexplained, and pointing at us.
23
- #
24
- # The row below is kept, but DISABLED, for three reasons:
25
- #
26
- # 1. Addressability. `disabled: true` keeps the row's id resolvable, so a
27
- # profile that wants to flip it on can do so with one edit instead of
28
- # inventing a row.
29
- # 2. It states the decision where the old attempt lived, where the next person
30
- # to wonder "why doesn't the pool bring up the compressor?" will look.
31
- # 3. It keeps `bili-native` (billion-context's own row) as the ONLY mount of
32
- # that module, which is the arrangement that actually works.
33
- #
34
- # CONSEQUENCE, STATED PLAINLY
35
- #
36
- # A profile that has not installed billion-context sees the billion card report
37
- # "not installed". That is the honest reading of the facts, and it is already a
38
- # first-class state on that page — the page distinguishes not-installed from
39
- # no-answer from ready precisely so this case reads as information rather than
40
- # as a bug. Installing billion-context remains a decision the user makes; the
41
- # pool no longer makes it for them.
42
- #
43
- # `src/billion-mount.ts` no longer calls `create()` for the same reason: with
44
- # this row disabled, a runtime create would fight the very row it sits beside.
45
- # The function still runs — it is what lets the card distinguish
46
- # already-installed from not-installed — it just never mounts anything.
47
- - id: billion-context-xdpool
48
- disabled: true
8
+ # billion-context is gone from this plugin, and so is the row that used to sit
9
+ # here (`billion-context-xdpool`, kept disabled).
10
+ #
11
+ # 2.0.0 inserted that row so a profile without the compressor would get one for
12
+ # free. Measured against a profile that had ALREADY installed billion-context —
13
+ # the normal state for anyone using it, since `bili-native` comes from that
14
+ # plugin's own `dsh.bundle.patch.yml` — the host did not disable the duplicate
15
+ # and did not resolve it to a no-op: it ran the fiber to `failed`, because the
16
+ # plugin registers a cordis service under its own name and a second registration
17
+ # is refused outright (`service "…" has been registered at <…>`). Every user who
18
+ # had installed it got a permanently failed entry, unexplained, pointing at us.
19
+ #
20
+ # The follow-up kept the row, disabled, "for addressability". That was the wrong
21
+ # trade: it left a name in this file for a feature the plugin no longer has, and
22
+ # the page that read it (`billion-context`) is deleted too. Installing the
23
+ # compressor is its own decision, made by installing it — which is the
24
+ # arrangement that always worked.