Repository navigation
Description
Owner: 待派(Lead 定)
#1249(修 #1245)让 moveSchedules 第一次去碰 DSH 的私有存储面:service.serialize() 里拿 (await service.getDomain()).table('tasks'),直接改写行 { ...task, sessionId: toId }。这条路是承重件——握手时任务能不能跟过来全靠它——但没有任何测试盯着它的形状。DSH 侧一改名或改形状,它不会红,只会静默停摆。
事实(本机 @deepseek-ai/dsh-schedule 0.2.1-rc.2,2026-10-26T06:4xZ 读)
- 两个成员在类型声明里就是 private:
lib/types/index.d.ts:125private getDomain;、:151private serialize;(相邻的:124private emitChanged;同样是 private)。 - 实现:
lib/index.js:2238async getDomain()、:2293serialize(work);table('tasks')的行形状{ sessionId, record, status, deliveryHistory }。 - 版本是精确 pin:
dsh-api-remotes、dsh-client-ui-schedule、dsh-client-ui-workspace、dsh-tool-schedule四个包都写"@deepseek-ai/dsh-schedule": "0.2.1-rc.2"(不是 range)。所以升级是一次显式动作——但升级时不会有任何东西提醒我们这条路可能已经废了。 - 本仓没有把它声明成依赖(
package.json/core/package.json/ds-bot/package.json里都没有),它是宿主注入的 service。
口径更正:交办里写的是
0.2.0-rc.2与d.ts:119/:132;实测是0.2.1-rc.2、:125/:151。按实测走。
失败形状(静默,不崩)
DSH 改名或改行形状 → service.serialize / service.getDomain 不存在或返回的形状变了 → moveSchedules 里抛错 → 外层 catch 只留一行 rt.warn('ds-bot: tasks of %s not moved: %s', fromId, …) → 任务留在正在被归档的旧 part 上,归档路径照样 stopActivity(#896 那条:core/test/part-archive.test.js 的 #896: a failed task move does not leave an armed earlier part active 断言"移动失败也不留一个 armed 的旧 part")→ 任务从此不再触发,界面上没有任何红。
更糟的是测试本身也照抄了这个形状:#1249 给 core/test/schedules.test.js 与 core/test/part-archive.test.js 的内存 fake 都加了 getDomain() / serialize(),字段也写成 { sessionId, record, status, deliveryHistory }。fake 与真模块同时改,所以现有用例抓不到 DSH 改名——绿的是 fake 自洽。
要的验收
- 一条对真模块(不是 fake)的断言:
getDomain与serialize存在且是函数,table('tasks')可读,行字段齐sessionId、record、status、deliveryHistory(record里至少id、title、kind、scheduledAt)。 - DSH 一改名/改形状,这条必须红,而不是跳过——skip 不算钉住。所以它得跑在真能 import 到
@deepseek-ai/dsh-schedule的地方(宿主/打包侧检查,而不是core/的常规单测环境);落在哪由 owner 定,但"环境里没有就 skip"不满足验收。 - 失败信息要点名「
getDomain/serialize在 0.2.x 上是 private,升级 DSH 时要重新确认moveSchedules的这条路径」,让下一个人不用重查。
关系
- 与
#1248(「承重但没钉住」)同类,互不重复:#1248钉的是review-gate的引用块护栏,本单钉的是 DSH 私有形状。 - 不阻断
#1249。#1249的 PASS 只要求把这条风险写进结论,并在docs/subsystems/core-host.md里留话——那份 diff 已经加了「Part move」一段(写明靠service.serialize改存储域里那一行),满足。 - 与
#1245(任务重新锚定)、#896(归档竞态)不重复:那两条是行为,这条是"行为的底座没有测试"。
不做
- 不改
moveSchedules的行为、不动#1249的代码; - 不把
@deepseek-ai/dsh-schedule加成本仓依赖; - 不删现有 fake——行为测试继续用 fake(它们测的是 FlyBot 自己的逻辑),本单只加一条盯真模块的钉;
- 不为此加 CI 矩阵或新 workflow,能找到现成的宿主侧检查点就挂在那里。
Activity
Birfy commentedon Oct 26, 2026
Owner: Dev (Lead decision)
Dev owns this after #1256 merges — both touch the same host task path (
core/src/host/tasks.js,core/src/host/task-drive.js), so they do not run in parallel.Shape to pin, from the issue body:
moveSchedulesreaches the row through(await service.getDomain()).table('tasks')and rewrites{ ...task, sessionId: toId }. The test must fail when that row shape or either private method (getDomain,serialize) disappears, not only whenmoveSchedulesthrows — today the outercatchinparts.jsturns a rename into onert.warnand the task is simply left on the archived part.check: pin the DSH task row a part handoff rewrites (#1257)
Birfy commentedon Oct 26, 2026
Claimed-by: Dev
Branch:
dev/feat/1257-dsh-task-shape@65fe284c6c47debf7efc38ff94cd74dfb68e5b7f, one commit onmain4095e1359a5a023c8e5d5ffb7ac7f8ff484f7c31(branch re-cut onto it; the earlier cut was off98528d9fand is superseded). Two files, +160/−0, both under.github/— nocore/, so nopatches/ds-bot/regeneration.What it will pin, from the issue body:
moveSchedulesrewrites a task row throughservice.serialize(...)and(await service.getDomain()).table('tasks')and puts{ ...task, sessionId: toId }back. Both members areprivateon dsh-schedule 0.2.x, and the row belongs to a storage domain declared inside the package, so a rename does not throw anywhere a test can see.Red plan (each alone, module mutated, check must exit 1):
getDomainrenamed →ScheduleService.prototype.getDomain is not a function.sessionId→session) → the rowmoveScheduleswrites is refused by the schema, naming the key.serializerenamed,statusvalue renamed, and the package absent → one line each, the last one failing rather than skipping.