Skip to content

feat(scheduled): 定时任务页改造为「任务 + 运行记录」主从视图(#1291 阶段一) - #1298

Merged
vastsa merged 8 commits into
vastsa:mainfrom
HanawaBanana:feat/scheduled-run-detail
Oct 2, 2026
Merged

vastsa merged 8 commits into
vastsa:mainfrom
HanawaBanana:feat/scheduled-run-detail

Conversation

@HanawaBanana

@HanawaBanana HanawaBanana commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

摘要

Issue #1291 的阶段一:把定时任务页改成「任务列 + 选中任务页」,让每次运行的结果留在页内可读,并把定时任务的会话从主界面的会话列表与全局搜索里收回去。之后按你的反馈补了会话模式、间隔周期,以及两处 UI 细节。

分支 feat/scheduled-run-detail,rebase 到 origin/main 3e34ca07d,共 3 个提交:

  1. feat(scheduled): read one task's runs inside the Scheduled page
  2. feat(scheduled): return from a run's conversation to its task
  3. feat(scheduled): add an interval cadence and a form that owns its page

refs #1291(阶段二、三仍未做,见文末)

包含内容

宿主

  • 会话摘要新增派生字段 scheduledRun:对 task_runs 做 EXISTS,不写入会话行。会话列表与全局搜索据此隐藏自动化转写,删除任务后转写自动回到普通列表,不会变得无法访问。
  • scheduled.listRuns 支持 { taskId, limit };scheduled.create/update 支持任务级会话模式 perRun / reuse(reuse 只在上一次会话仍存在、且仍属于同一项目时继续,否则新开)。
  • 新增 interval 周期与 schedule.intervalMinutes(5–1440 分钟,按经过时间排程;interval 缺少该值时写入被拒绝,而不是存成一个永不触发的任务)。AI 工具 ScheduledTaskCreate/Update 的 schema 同步放开该周期与字段。

渲染层

  • 定时任务页:任务列 + 选中任务页(事实、指令折叠、本任务运行记录),页内按有界读取展示所选运行的转写(最新 60 条、每字段 20 000 字符);仍在运行的那次转写按运行自身状态每 5 秒跟进,并有 revision 保护避免迟到响应覆盖新数据。
  • 会话列表、搜索面板的「最近会话」、托盘最近列表都走同一条归属判定:定时任务的转写不会被当成可切换的对话列出(渲染层 listableSessions,主进程 trayVisibleSessions)。
  • 对话顶部栏在自动化会话上提供返回入口:标注目标页面,已知来源时还标注所属任务;返回后恢复同一个任务与同一次运行,紧邻时沿导航历史后退。
  • 编辑表单打开时独占页面(任务列与任务页不再渲染在表单下方);间隔以「数量 + 分钟/小时」表达;选中任务与选中运行在两种主题下都用「强调色底纹 + 前缘竖条」表达(亮色下原来的抬升底板是白底白,等于没有选中效果)。

文档 / 测试

  • 中英双语文档:ui-ia §3.3、component-spec §20A(状态表与交互)、data-storage §4.11、E2E 计划场景。
  • 新增/更新用例:宿主 timing 与 automation 的间隔语义、宿主工具 schema、渲染层的间隔显示与编辑表单、i18n 审计;9 种语言共 12 个新键。

未包含(后续阶段)

  • 会话压缩检查点里的 Todo 快照与 Goal 续跑提醒(打算单独开 PR)。
  • 运行记录的跨项目总览与筛选。

验证

任务候选基于 origin/main 82f94b4ba(已把 main 合并进分支,pnpm check:pr-base 通过):

  • pnpm build:js、pnpm lint、pnpm --filter @pi-desktop/desktop typecheck、pnpm docs:check(546 页)
  • pnpm --filter @pi-desktop/desktop test — 3410 通过
  • pnpm --filter @pi-desktop/i18n test — 29 通过;pnpm --filter @pi-desktop/shared test — 1158 通过
  • cargo test -p host-core --locked — 741 通过;cargo fmt --check
  • 后续补的 latestPerTask 修复另加两条 host 用例:全局窗口丢任务 vs 每任务最新一条、latestPerTask 与 taskId 互斥

真机验证(zh-CN、独立配置目录、本地 SSE 夹具模型,建了 3 个任务,其中一个为 30 分钟间隔任务):

REUSE_SESSIONS ["86e70494-…"]        # 复用模式下两次运行写进同一段会话
SIDEBAR 只列出用户自己的对话,未出现任何定时任务转写
BACK_ROW {"label":"定时任务","tooltip":"返回定时任务 · 每周 PR 巡查"}
BACK_TARGET 返回前后完全一致(同一任务 + 同一次运行)
INTERVAL_ROW "依赖扫描 · 间隔 / 每 30 分钟 / 尚未运行"   # 不再拼 00:00 占位时钟
SELECTED_SURFACE 选中 oklab(0.907065 …) + rgb(26,28,31) 2px inset;未选中 rgba(0,0,0,0)
EDITOR_FIELDS {"intervalField":true,"value":"30","unit":"分钟","cadence":"间隔","rowVisible":false}

(后续补测:给一个任务塞 140 条更新的完成记录、把另一任务记录整体前移 200 分钟,任务列里空闲任务仍显示「已完成 · 3小时前 · 1s」而非「尚未运行」。)

已知问题(都先于本 PR 存在于 main)

  1. scripts/check-architecture.mjs 失败 —— 这条是我本地 main 引用过期(还停在 v0.15.10)造成的误判:用 PR 的 base 作为参照跑 check-architecture 是通过的(New TS/TSX files checked: 12),CI 的四项检查也全部通过。已在下面更正。
  2. scripts/e2e-scheduled.mjs 在 main 上已过期:它仍在 .composer-menu-entry 里找 Reasoning 项,而 UI 早已换成推理等级滑块(参见 ComposerModelPicker.tsx 里 [Feature] 推理等级交互优化 #417 的注释)。所以上面的端到端结论来自我自己的真机脚本,而不是这个脚本。
  3. 构建产物相对路径少一级 —— main 的 fix(electron): resolve main output root from inside Rollup chunks #1307(fix(electron): resolve main output root from inside Rollup chunks)已经修好这一条;我删掉了当时为跑真机临时补齐的构建产物,最近一次真机验证是在干净构建上跑的。

AI 辅助说明

本 PR 的实现、文档与验证由 AI 编码代理协助完成:模型 deepseek-v4.1-flash,思考程度 max。上面所有命令与真机结论都是我在本地实际执行的;已知失败项(架构检查、过期 E2E 脚本、构建产物路径)也照实列出,没有隐藏。

The Scheduled route could only list tasks beside one global run feed, so
checking a single automation meant switching tabs, scrolling a history that
mixed every task, and leaving the page to read a result. It now pairs a task
column with the selected task's own page: last outcome and duration, next
occurrence, instruction, that task's own runs, and the selected run's
transcript read in place through a bounded session read.

A run's transcript is the automation's output, not a conversation the reader
started, so the host now reports `scheduledRun` on every session summary and
search hit. The flag is derived from `task_runs` on read and never stored on
the session row, which keeps the ownership honest and returns a task's
transcripts to the ordinary lists when the task is deleted.

refs vastsa#1291
The Scheduled route owns a run's transcript and the session list is no longer
an entry point to it, so the chat surface needed its own way back: a scheduled
run's conversation now shows a back row in the top bar. It names the route and,
when the run row itself was the origin, the task the run belongs to. Returning
restores that task and that run — the exact row the reader was reading — and
steps back through the navigation history when this route is directly behind
the conversation.

Conversation ownership becomes an explicit per-task setting in the same change:
a task either opens a new conversation for every run or continues one, and the
reuse path only continues a session that still exists and still belongs to the
task's project. The editor states the choice beside the task's other execution
facts, and the task page reports it with the run it produced.

refs vastsa#1291
A task could only run on a clock, so "every 30 minutes" had to be approximated
with an hourly task. An interval cadence now states its own span as a count
with a minute or hour unit (5 minutes to 24 hours, stored as minutes), counts
from the moment it was armed, and is refused without its value instead of being
saved as a task that never fires. The task row reports the span rather than a
clock, and the value rides along with every armed cadence, so switching a task
between a calendar and an interval loses neither.

Opening the form also left the task column and the task page rendered below it,
competing with the draft; the form owns the page while it is open. The selected
task and the selected run gained an accent tint with a leading bar, because the
previous raised fill was white on white in the light theme and read as no
selection at all.

refs vastsa#1291
@vastsa

vastsa commented Oct 2, 2026

Copy link
Copy Markdown
Owner

感谢提交并附上了详细验证记录。我核对了 PR 与 #1291 的需求,当前变更覆盖了按任务读取运行记录、页内转写、侧栏/搜索过滤,以及删除任务后恢复会话可见性的主要路径。

审查发现一处可复现的边界问题:use-scheduled-workspace.ts 把 rail 的运行读取限制为全局最近 100 条(RAIL_RUN_LIMIT),再由 latestRunByTask 推导每个任务的最近状态;因此若某个任务的最后一次运行已落在这 100 条之外,ScheduledTaskRail 会把它显示为“从未运行”。需要让每个任务都能取得其最新一条记录(例如由 host 提供每任务最新运行结果的有界查询),避免全局截断造成错误状态。

另外,仓库当前 AGENTS.md §15(临时政策,自 2026-09-26 生效)将无写权限贡献者的 PR 限定为 perf 与 fix;维护者定向的自动代理工作除外。根据 GitHub 当前权限信息,PR 作者为只读权限,而本 PR 类型为 feat,因此不能作为 landing candidate。按该政策我关闭此 PR;这不代表关联 issue #1291 已解决或关闭。

@vastsa

vastsa commented Oct 2, 2026

Copy link
Copy Markdown
Owner

按仓库 AGENTS.md §15 的临时外部 PR 类型政策关闭;上方审查评论记录了权限原因及已发现的最近运行状态问题。

@vastsa vastsa closed this Oct 2, 2026
@vastsa vastsa reopened this Oct 2, 2026
@vastsa

vastsa commented Oct 2, 2026

Copy link
Copy Markdown
Owner

更正:PR 作者是受维护者授权的定向开发贡献者,因此适用 AGENTS.md §15 的维护者例外。此前以外部贡献者类型政策为由关闭 PR 是我的判断错误,我已重新打开 PR。前条留言关于作者权限/PR 类型的限制不适用于此 PR,请忽略该部分。

代码审查发现的运行状态问题仍有效:任务列从全局最近 100 条运行记录推导每个任务的最近状态,因此最后一次运行落在窗口之外的任务会误显示为“从未运行”。请修复后再继续合并审查。

The task column derived every row's outcome from one global window of the
newest 100 runs, so a task that had been idle while other tasks produced runs
was reported as never run — and a task whose run scrolled out of the window
lost its running indicator the same way. `scheduled.listRuns` now answers
`latestPerTask`: one newest run per task, independent of how much history the
table holds, which is what the column reads. The single-task history read and
the global window keep their previous shapes.

Reported by @vastsa while reviewing vastsa#1298.

refs vastsa#1291
@HanawaBanana

HanawaBanana commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor Author

回复 review 里「最近运行状态」那条:确认是真实缺陷,已经修好,分支也更新了(head 现在是 6a8880bbf)。

原因:任务列原来读的是 scheduled.listRuns({ limit: 100 }) 这个全局窗口,再从窗口里推出每个任务的最近状态。只要别的任务在这段窗口里产生了 100 条更新的记录,空闲任务的行就不在窗口内,于是显示成「尚未运行」;同一原因也会让一个仍在运行的任务丢掉运行中标记。

修法按你的建议做成 host 侧有界读取:

  • scheduled.listRuns 增加 latestPerTask:每个任务各返回最新一条,与 taskId 互斥(同时传会被拒成 INVALID_PARAMS),返回条数只跟任务数相关。
  • 任务列改读这个形状;单任务历史读取(taskId)与原来的全局窗口两种旧形状保持不变,其他调用方不受影响。
  • 顺带删掉 hook 里那个 100 的常量,避免以后再被当成「每个任务的最近状态」用。

验证:

  • host 测试:一个空闲任务 + 一个繁忙任务(120 条更新的记录)——断言全局窗口里只剩繁忙任务的记录,而 latestPerTask 同时返回两者各自的最新一条。
  • RPC 测试:latestPerTask 每任务一行;与 taskId 同传被拒。
  • 真机(zh-CN、独立配置、本地夹具模型):先用 sqlite3 给一个任务写入 140 条更新的完成记录、把另一个任务的记录整体前移 200 分钟,再启动应用——任务列里那个空闲任务显示「已完成 · 3小时前 · 1s」,不再是「尚未运行」。
  • 回归:desktop 3404、host 738、i18n 29、shared 1158、docs 546 页,typecheck / lint / build:js / cargo fmt --check 全通过。

另外看到 PR 又被打开了。AGENTS.md §15 的类型政策我理解,如果这条仍然适用,我这边不做额外动作;如果需要我按别的方式配合(比如拆成 fix 范围的 PR,或者你直接取这个分支),说一声就可以。


补充两点:

  • 分支已把 origin/main(601d5e5f7)合并进来,pnpm check:pr-base 通过;CI 的四项检查(Docs、Head contains latest base、JS build/typecheck/lint/architecture/test、Rust host-core)现在全部通过。
  • 更正我之前在描述里写的一条:check-architecture 失败是我本地 main 引用过期(停在 v0.15.10)造成的误判,以 PR base 为参照跑它其实是通过的(New TS/TSX files checked: 12)。描述里已经改掉了。

vastsa
vastsa previously requested changes Oct 2, 2026

@vastsa vastsa left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查结论:实现方向、宿主契约和测试都站得住,但有 3 处需要先修(都在本 PR 自己写下的承诺范围内),另有 2 处需要定一下边界。修完我再合入。

我的验证(把 origin/main 9c4093bd0 合进 PR head 7162dc65 的本地 worktree 上跑)

  • pnpm build:js、pnpm --filter @pi-desktop/desktop typecheck、pnpm lint 通过;cargo test -p host-core --locked — 741 passed。
  • desktop 测试 3407 项:3406 通过,唯一失败是 npm-executable.test.mjs 的「5 秒预算」用例在并发跑测时超时(4981ms > 5000ms 预算),单独重跑 12/12 通过 —— 负载下的偶发,与本 PR 无关。
  • i18n:9 个语种新增 30 个键完全对齐,无缺失/多余,非英语语种是真实翻译。
  • 派生标记:scheduled_run 只在三处 SQL 读取(sessions.rs:1238/1452、session_search.rs:100),都带 AS scheduled_run;其余构造点显式 false;旧 host 缺字段时为 undefined,渲染层用 === true(session-origin.ts:21、ConversationTopbar.tsx:97),不会误藏。
  • 删除语义成立:task_runs.task_id CASCADE + session_id SET NULL,删任务确实把转写放回普通列表;reuse 只从 task_runs 取且校验 deleted_at/项目,begin_run 失败只清理本次新建的会话。
  • latestPerTask 与 taskId 互斥、走 (task_id, started_at DESC) 索引,任务列不再读全局窗口 —— 之前那条缺陷已修好。
  • 注意:head 现在不含最新 main(main 已前进到 9c4093bd0),合入前需要先把 main 合进分支。

需要先修

  1. Cmd+K 的「最近会话」仍然列出并能进入自动化转写。 apps/desktop/src/components/SearchDialog.tsx:148:const source = q ? search.hits.map((hit) => hit.session) : sessions; —— 空查询走的是 store 全量 sessions,而过滤只加在 apps/desktop/src/hooks/use-session-search.ts:35 的命中那一路上。自动化会话的 updatedAt 通常最新,进前 30 条,所以打开搜索面板第一屏就能看到、也能切进去。托盘同样:apps/desktop/electron/main/tray-sessions.ts:89,102 直接用 session.list 的结果构建「最近会话」。这与本 PR 写进规范的句子冲突(docs/spec/04-ux/01-ui-ia.md §3.3「the SessionList and global session search never list it」、docs/spec/04-ux/08-component-spec.md §6)。建议复用同一判定:渲染层用 isAutomationSession,托盘在 main 进程里内联 session.scheduledRun === true。

  2. 英文规范有一处重复残句。 docs/spec/04-ux/01-ui-ia.md:266-268:…and whether it is paused or / running. 之后第 268 行又出现 whether it is paused or running. The task page shows…。应删掉重复片语,让 268 行从 The task page shows 开始。

  3. 中文规范两处与英文版不一致/被截断。

    • docs/zh-CN/spec/04-ux/01-ui-ia.md:213 段落以「…以及暂停或运行中状态;」结束就没了:英文版接着写的「任务页显示最近一次运行、下次执行、项目、权限、模型、指令折叠、本任务运行历史、页内读取转写、返回入口、侧边栏时钟与全局搜索进入本页、立即运行停留在本页」整段在中文版缺失;原来那句「侧边栏时钟与全局搜索均可进入」被删掉后没有替换。
    • docs/zh-CN/spec/03-runtime/04-data-storage.md:919-920:config_json 保存 schedule: {hour, minute, weekday} 后面直接接 `workspacePath`、会话模式…,中间丢了 nextRunAt(毫秒时间戳)与 intervalMinutes(5–1440),与英文版不一致,而下一段已经在用 intervalMinutes × 60_000。

    (顺带一个小语病:docs/spec/06-delivery/04-e2e-test-plan.md:432 的 pause/resume; Run now / select an interval cadence… 读起来像「Run now select…」,补个分号即可。)

需要定边界(已确认存在,但不算回归,可以选择不在本 PR 修)

  1. 保留策略会让旧转写回到侧栏。 crates/host-core/src/db/migrations.rs:4,116-124 每次打开数据库按任务只保留最近 100 条 run。被删掉 run 的会话随即失去 scheduled_run 标记,于是下次启动后它们重新出现在侧栏;同时这些 run 已不在任务页的历史里(行已删)。按新加的间隔周期算:interval 5 分钟约 8 小时、30 分钟约 2 天、hourly 约 4 天就会发生。改动前它们本来就在侧栏,所以不是回归,但和「转写只在定时任务页」的承诺不一致 —— 要么在 data-storage §4.11 / component-spec §20A 写明这条边界,要么按你之前在 #1291 里的思路,用持久的 origin 字段解决。

  2. TASK_RUN_LIMIT = 200(host clamp 1..200):进程长时间不重启、某任务 run 数超过 200 时,第 200 条以前的 run 的转写在页内历史里读不到(下次启动被 prune 后又冒回侧栏)。窗口很窄,同第 4 条一起看即可。

  3. 两个小点,不影响合入:搜索是在渲染层按页过滤(整页都是 automation 命中时用户看到 0 条但仍需点「加载更多」,host 侧过滤可消除);task_runs(session_id) 没有索引,新增的 EXISTS 每行查一次(当前量级无碍)。

未做

真机 E2E 我没有跑(worktree 里没有补构建产物);scripts/e2e-scheduled.mjs 仍在找已经取消的 Reasoning 菜单项,这条在 main 上就存在,与本 PR 无关。

改好 1–3(第 4/5 条如果决定只写文档也请在 PR 里说一声),并把 main 合进分支后回我,我核对 CI 后合入。

The Command-K recents view and the tray still offered a scheduled run's
transcript, because only the SessionList and search hits applied the ownership
rule: the palette's empty-query list reads the store directly, and the tray
builds its recents from `session.list`. Both now go through the same rule — one
`listableSessions` helper in the renderer and its main-process twin for the tray
— so no session list offers a conversation that belongs to the Scheduled page.

Also repairs the spec text an earlier change left truncated (a duplicated English
fragment, the Chinese UI/IA paragraph and the config_json field list), records
the retention boundary a fast cadence reaches — a pruned run takes its session's
ownership marker with it and that transcript returns to the ordinary lists — and
indexes `task_runs(session_id)` for the ownership probe that summaries and
search run per row.

Reported by @vastsa in review of vastsa#1298.

refs vastsa#1291
@HanawaBanana

Copy link
Copy Markdown
Contributor Author

三条必修项都改好了;4/5 我选择只写文档,第 6 点里补了一个索引。main 已合并(82f94b4ba),pnpm check:pr-base 通过,head 现在是 33834b8f1。

1. Cmd+K 的最近会话 / 托盘

确认属实,两处都绕过了归属判定:搜索面板空查询读的是 store 全量 sessions(只有命中那一路过滤了),托盘则直接用 session.list 的结果构建最近会话。

改法:新增共用判定 listableSessions(apps/desktop/src/lib/session-origin.ts),SessionList 与搜索面板的最近列表都走它;主进程加了同样的 trayVisibleSessions(渲染层模块不能直接引入),托盘在 sessions = … 处过滤。

测试:listableSessions 的行为用例(只丢 scheduledRun === true;缺字段与显式 false 都保留)、Sidebar 与搜索面板的接线断言,以及新增的 tray-session-visibility.test.mjs 单测。

这里我没有顺手动 Projects 页:项目索引里的会话列表与计数属于项目管理面(涉及批量删除与「N 个会话」),把它们排除出去会改变计数语义。如果你认为那里也该排除,我按你的结论改。

2. 英文规范重复残句

已删掉重复片语,docs/spec/04-ux/01-ui-ia.md 现在从 running. The task page shows that task's last run, next… 接下去。

3. 中文规范截断 / e2e 语病

  • docs/zh-CN/spec/04-ux/01-ui-ia.md:213 补回整段(任务页显示、转写归属、返回入口、侧边栏时钟与全局搜索、立即运行),逐任务读取那句并入其中;
  • docs/zh-CN/spec/03-runtime/04-data-storage.md 的 config_json 列表补回 intervalMinutes(5–1440)与毫秒时间戳 nextRunAt;
  • e2e 步骤重排,pause/resume; Run now and read the admitted run's transcript… 不再被插断,间隔步骤接在其后。

4 / 5. 边界:选择只写文档

理由是持久化 origin 需要会话表迁移,还会牵扯远程会话与 fork/复制语义,不适合塞进这个已经很大的 PR。已写进:

如果你希望这次就上持久化 origin,我可以单独开 PR,不动这个分支。

6. 两个小点

  • task_runs(session_id) 加了偏索引 CREATE INDEX IF NOT EXISTS idx_task_runs_session ON task_runs(session_id) WHERE session_id IS NOT NULL,放在 boot maintenance,不需要迁移版本。
  • 搜索的 host 侧过滤没有改:那会改变搜索的命中集与分页语义(host 契约),而可见契约已由渲染层保证,按你说的「不影响合入」处理;需要的话另开 PR。

验证(干净构建)

  • pnpm build:js、typecheck、lint、docs:check(546 页)、check:pr-base
  • desktop 3410 通过、host 741 通过、i18n 29、shared 1158、cargo fmt --check
  • 真机(zh-CN、独立配置、本地夹具模型)完整脚本:这次是干净构建 —— fix(electron): resolve main output root from inside Rollup chunks #1307 正好修掉了我上次提到的构建产物路径问题,之前的临时补丁已经删掉。包含你指出的场景:给一个任务写入 140 条更新的记录、把另一任务记录整体前移 200 分钟,任务列里空闲任务显示「已完成 · 3小时前 · 1s」而不是「尚未运行」。其余断言(复用会话同一 id、侧栏无转写、返回入口恢复同一任务与同一运行、间隔行「每 30 分钟」、亮色选中强调色底纹 + 前缘竖条、表单独占页面且间隔字段 30/分钟)也都通过。

我这边没有别的异议了,麻烦你再核一遍。

The reordering left the previous three lines in place, so the step list repeated
"fields and verify its first occurrence is one hour away; pause/resume; Run now"
and trailed off at "conversation, use model tool calls…". Restores the original
"observe automatic completion; delete the settled task." step, which the Chinese
plan still states.
@vastsa

vastsa commented Oct 2, 2026

Copy link
Copy Markdown
Owner

三条必修项都在 da6a883a2 里处理好了,我核过一遍:

  • Cmd+K 最近会话 / 托盘:listableSessions 落在 session-origin.ts,SessionList 与搜索面板的最近列表都走它;主进程加了 trayVisibleSessions 这个 twin(渲染层模块不能直接引入),托盘在 sessions = … 处过滤。判定语义正确:只丢 scheduledRun === true,缺字段与显式 false 都保留。
  • 英文 / 中文规范:重复残句已去掉;zh-CN 的 UI/IA 段落补回任务页、转写归属、返回入口与「侧边栏时钟与全局搜索」「立即运行停留本页」;zh-CN config_json 补回 intervalMinutes 与毫秒时间戳 nextRunAt。
  • 保留边界:data-storage §4.11 写明按任务保留 100 条、被清理的运行会同时离开任务历史并让该会话失去 scheduledRun(转写回到会话列表与搜索)、单任务读取上限 200;component-spec §20A 给了摘要并指向 §4.11。task_runs(session_id) 的偏索引加在 boot maintenance,和相邻的 turns(ended_at) 索引同一处、不需要迁移版本。这些处理我接受。
  • Projects 页与 host 侧搜索保持现状,你的理由(项目管理面的计数语义、host 搜索命中集与分页契约)我同意,不阻塞合入。

本地核验(head 26768614e):

  • pnpm build:js、--filter @pi-desktop/desktop typecheck、pnpm lint、pnpm docs:check(546 页)全部通过;desktop 3410 通过、0 失败。
  • cargo test -p host-core --locked 741 通过、cargo fmt --check -p host-core 干净。
  • 新用例我单独重跑过:tray-session-visibility.test.mjs 与 scheduled-workspace.test.mjs 里的接线断言都在。

我在你的分支上补了一个提交(26768614e,未改任何逻辑):docs/spec/06-delivery/04-e2e-test-plan.md 这次重排把原来的三行留在了原处,于是步骤里出现了重复的 fields and verify its first occurrence is one hour away; pause/resume; Run now / select an interval cadence, enter 30 minutes…,并在 conversation, use model tool calls… 处断句;同时上一版删掉的 observe automatic completion; delete the settled task. 没有回来(中文版这一步还在)。现在两处都对上了。

CI 四项已经在这个 head 上全绿,我这就合入。

@vastsa
vastsa dismissed their stale review October 2, 2026 15:04

复核通过:三条必修项已在 da6a883 改好,本地与 CI 全部通过;另外补了 e2e 步骤的重复文本修复(26768614e)。

@vastsa
vastsa merged commit b885bbb into vastsa:main Oct 2, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants