Skip to content

feat(desktop): 任务级上下文窗口档位(内核) - #4598

Merged
MagicLizi merged 14 commits into
makecindy:mainfrom
zyjisdog:feat/session-context-window
Oct 24, 2026
Merged

MagicLizi merged 14 commits into
makecindy:mainfrom
zyjisdog:feat/session-context-window

Conversation

@zyjisdog

@zyjisdog zyjisdog commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

feat(desktop): 任务级上下文窗口档位(内核)
---HEAD: feat/session-context-window

拆分说明(2026-10-23,按维护者要求):本 PR 原为 +5159 行的单体,已拆为三部分:

  1. 本 PR(内核):存储、边界解析、各 agent 接入、fork / worker、device-link 命令面;
  2. UI PR feat(desktop): 任务级上下文窗口档位 UI:ContextWindowBudgetChip #7011(ContextWindowBudgetChip 与挂载,附亮/暗色截图);
  3. 底栏基建 PR feat(desktop): 底栏状态卡基建:focusTraversal、statusBarCards、popover portalContainer #7006(focusTraversal / statusBarCards / popover portalContainer / TodaySpendChip):与本功能无直接耦合,独立提审。
    此前 8 轮对抗性 review(Greptile / Codex)的修复全部包含在本 PR 与 feat(desktop): 任务级上下文窗口档位 UI:ContextWindowBudgetChip #7011 中。

合入顺序:本 PR 与 #7006(基建)互不依赖、可并行合入;#7011(UI)依赖两者合入后 rebase,diff 会自动收敛为 UI-only。

最终 UI 形态(亮/暗,fork pr-assets 孤儿分支):

chip · 亮
chip · 暗
档位卡 · 亮
档位卡 · 暗

这次改了什么

摘要

给单个任务加「工作上下文窗口档位」的内核:任务可以选择本任务最多用多大的上下文窗口(tokens),与设置页的自动压缩阈值百分比正交——档位决定分母/容量,百分比决定触发点。

动机:分档计费模型的窗口档位直接决定价带(如 Qwen3.7 Plus ≤256K / >256K 单价差 3 倍);不分档模型把任务压到更小运行窗口可降低平均每轮成本。

关联 Issue:#3464(维护者结论:产品缺口是任务级策略与入口,contextWindow 必须继续来自目录,不能由 session 数据库改写)。本 PR 落任务级入口,且从不超过目录 contextWindowMax。

范围

  • 存储:main 侧偏好文件(owner 隔离 userData 下 session-context-budget-prefs.json),读写集中在 session-context-budget-store.ts;不新增数据库迁移、不改 schema、不写会话行(DB 模式停在官方 0113)。
    • 为什么不是会话列:任务预算若进迁移链,库一旦记上本分支独有的迁移,任何不带该迁移的包启动会以 applied migration runtime identity changed at seq ... 拒绝启动。任务级窗口是纯客户端偏好,不该换来不可逆的库状态。
  • 边界解析:有效窗口 = min(任务预算 ?? 模型级上限, 模型级上限, 目录 contextWindowMax);resolveSessionContextWindowBounds / resolveRouteContextWindowBounds;contextWindowMax 原始字段不进 renderer 投影,main 解析出的有效上限随 bounds 下发(renderer 永不自行推导窗口)。
  • 三引擎接入:
    • Pi:预算 → compaction.reserveTokens(热切实时改 + 切后重载 fail-closed);宿主不做强制重建(引擎自己的 requiresModelSwitchRebuild 标出重建需求);
    • Claude Code / Codex:env 下发 + 路由变化时按目标路由重新收敛,目标窗口与当前不同则强制重建;
    • 切模预演与 switchModel 使用同一份目标路由收敛预算(外层预演不再用引擎持有的旧预算,修「Pi 首次切模发送失败」)。
  • 应用时机:保存后空闲 → 冷重建;回合中 → 登记 pending、turn 结束生效。fork 继承 + 失败回滚;Orca worker 唤醒与常规启动共用 applySessionContextWindowBudgetToCreateOpts。
  • device-link 远程命令面:新 channel maker:set/get-context-window-budget(allowlist 单向新增);控制端经隧道让被控端写自己的偏好并应用;老被控端回 CHANNEL_NOT_ALLOWED。远程「只能收紧」仅发生在拿不到被控端权威边界时(老被控端 / 拉取失败)。
  • 明确不在本 PR:renderer 档位 chip 与交互(UI PR)、底栏卡片基建(基建 PR)、移动端 / IM / 定时任务入口。

UI 变化

  • 引用的设计规范:不涉及:本 PR 为内核(存储/边界/引擎接入/协议),renderer 侧仅 sessionService.ts 的类型字段与 vite-env.d.ts 的 IPC 类型声明,无任何组件、样式、布局、文案改动。

变更类型

  • feat 新功能

怎么验证的

自动验证

手工验证

  • dev 实机验证过完整功能(含 UI):档位保存后 reserveTokens 生效、切模收敛、fork 继承、worker 唤醒预算透传、远程收紧口径(第 8 轮用户实测报障的交互问题已在 UI PR 修复)。

未执行的验证

  • 无(相对原单体 PR 无新增未验证面;UI 相关验证随 UI PR)。

风险

风险分类

  • 无已知风险
  • SQLite / migration(本 PR 无 schema / 迁移改动)
  • system prompt
  • 协议兼容(device-link allowlist 单向新增 channel,老被控端按 CHANNEL_NOT_ALLOWED 降级)
  • 权限 / 安全 / 用户数据(偏好文件 owner 隔离,见 credentials-and-local-storage 规则)
  • 存量插件兼容
  • 原生层 / fingerprint / OTA
  • 跨平台差异
  • 其他:任务运行时行为(工作窗口变小会提前触发压缩)

影响与回滚

偏好文件是新增文件,回滚 = 删文件 + 回退代码;不触碰 DB、迁移链与已有 channel 语义。无预算(null)任务行为与现状完全一致。

提交前检查

  • 仓库规则已读:docs/dev-rules/database-and-migrations.md(无迁移)、docs/dev-rules/protocol-compatibility.md(allowlist 单向新增)、docs/dev-rules/maker-core-and-agent-behavior.md(本 PR 一并更新)、docs/dev-rules/pi-harness.md(Pi 原生能力非退化)。
  • pnpm check:dco 通过。

@zyjisdog
zyjisdog requested a review from a team as a code owner September 17, 2026 06:33
@greptile-apps

greptile-apps Bot commented Sep 17, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] 本轮修改看起来可以合并,未发现新增的阻塞问题。

Summary

本 PR 为单个任务加入上下文窗口预算,覆盖偏好存储、窗口边界解析、三类引擎、fork、worker 恢复及远程命令。

  • Each task can save a context window budget bounded by its model route.
  • Pi, Claude Code, and Codex use the task budget when their model route changes.
  • A saved budget change updates live tasks now or at a later send boundary.
  • Forked tasks inherit the source task’s saved window budget.
  • A controller can read route bounds and set a task budget on a linked device.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[本地或远程保存任务预算] --> B[按账号隔离的偏好文件]
  B --> C[按目标模型与来源收敛窗口]
  C --> D{任务是否正在运行}
  D -->|空闲| E[关闭实例,下次发送重建]
  D -->|回合中| F[保留待应用预算]
  F --> G[安全边界应用]
  C --> H[启动与恢复时传给引擎]
Loading

Reviews (43) · Last reviewed commit: "test(desktop): fork 用例把未登录态 temp 路径也隔离到每..." · Reviewed by Greptile

Comment thread apps/desktop/src/main/maker-ipc/register.ts
Comment thread apps/desktop/src/renderer/lib/statusBarCards.ts Outdated
Comment thread apps/desktop/src/renderer/components/status/ContextWindowBudgetChip.tsx Outdated
@MagicLizi

Copy link
Copy Markdown
Contributor

本 PR 命中维护者确认门(产品 / UI、规则文档、架构),已开讨论 issue,请维护者在本 PR 上 Approve 放行;需要修改请 Request Changes。

讨论 issue:#4601

@MagicLizi MagicLizi added awaiting-discussion 等待维护者讨论(review-pr) touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:large-diff 改动量较大(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) touches:redline 改动碰到红线路径(updater / DB schema 等,review-pr 自动维护,仅展示) touches:rules 改动碰到规则 / 规范文档(review-pr 自动维护,仅展示) labels Sep 17, 2026
@zyjisdog

Copy link
Copy Markdown
Contributor Author

@greptileai review — 请基于当前 head 92b55311d 再评审一轮。

上一轮 3 条意见的处置(逐条已在对应 thread 回复):

  1. P1「远程调用绕过会话授权」(register.ts)→ 判定为本 PR 范围之外,不改:远程命令面是设备级信任(同账号 + 被控端显式开启远程控制 + 未撤销 + allowlist 四道门),allowlist 里既有 maker:set-permission-mode(可放宽审批)、maker:set-extra-dirs / maker:set-writable-dirs、maker:send / maker:steer 等会话变更型 channel,门禁与本 PR 新增的两条完全相同,而能力更强;仓库里也不存在「未向控制端开放的任务」这一模型(maker:get-session-tree / maker:list-active 本就放行)。要做会话级授权是整个 181 条 channel 的口径变更,已说明愿按维护者裁决另开一版。若你认为这两条在多出的具体路径上越权(例如绕过 assertReviewSettingsUnlocked),请指出路径。
  2. P2「同类卡片无法互斥」→ 已修:协调器改为按实例登记(句柄 + token),并加注销守卫;分屏 / Orca 同时挂载两份底栏时,后展开的那张会关掉先展开的。新增 apps/desktop/src/renderer/lib/__tests__/statusBarCards.test.ts 7 例。
  3. P2「单选组缺少键盘导航」→ 已修:档位行补 roving tabindex(组内单一 Tab 停靠点,落在当前选中档)+ ArrowUp/Down/Left/Right/Home/End 移焦点(键盘处理挂在浮层上,因为 Radix 把初始焦点给内容容器而非行)。方向键只移焦点不提交(每次提交都会落库并可能触发活实例重建,扫一遍档位不该连写多次库;与换 Popover 前的 Radix 菜单行为一致),Enter/Space/点击才提交。chip 用例 22 → 31。

本轮其它变化: CI 首轮红的根因是 4 个手写 CREATE TABLE sessions fixture 未同步新列(localDb 用例不在 unit tier,本地 vitest related 选不中),已修并逐个跑通;当前 CI 全绿、DCO 过、MERGEABLE。PR 描述也统一了「菜单能否选到高于模型默认的档位」的表述(可上可下,上限只有一道;唯一只能收紧的场合是远程拿不到被控端权威边界)。

@zyjisdog

Copy link
Copy Markdown
Contributor Author

@codex review

@zyjisdog

Copy link
Copy Markdown
Contributor Author

关于本轮 Windows unit tests (2/2) 的红灯:基础设施 flake,与本 PR 无关,重跑已触发。

证据(该 job 日志):

  • Test Files 1366 passed (1366)、Tests 19537 passed | 46 skipped (19583) —— 用例全过;
  • 唯一的错误是 vitest 自身的 worker 通道超时:Error: [vitest-worker]: Timeout calling "onTaskUpdate",vitest 把它记成 Errors 1 error,scripts/test-workspaces.mjs 归类为 TEST_ASSERTION_FAILED;
  • 同一次 run 里 Linux unit tests (1/2)、Linux unit tests (2/2)、Windows unit tests (1/2)、verify、verify-checks、Desktop Git integration 全过。

本机全量 desktop 单测上还观察到两个同类上游 flake(两轮各挂 1 / 2 例,且两轮互不相同),均为上游 main 的既有测试、git diff d1fd9c91e 为空、单独跑通过:

  • pi-package-store-security.test.ts > keeps the maximum package roster projection bounded(重负载下投影断言失败);
  • piEnvironment.test.ts 两例 fetch failed → Error: bad port(随机端口撞上 undici 禁用端口名单)。

这两处不属于本 PR 的改动范围,本 PR 未改动上游测试。

@zyjisdog zyjisdog closed this Sep 17, 2026
@zyjisdog zyjisdog reopened this Sep 17, 2026
zyjisdog added a commit to zyjisdog/cindy that referenced this pull request Sep 19, 2026
Upstream-PR: makecindy#4598
Upstream-PR-Head: 6e5c18d
Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
zyjisdog added a commit to zyjisdog/cindy that referenced this pull request Sep 19, 2026
本地构建曾把 makecindy#4598 的「任务级上下文窗口档位」迁移落成 0108_loose_puppet_master.sql;
之后该分支合入上游时,主干已在 0108 放了 bot 私聊迁移(0108_lowly_scarlet_witch.sql),
同一 schema 意图被重编号到 0110_green_unus.sql。于是「用旧包升级过、又换新包」的库会在
prepareMigrationRuntimeManifest 处以
`applied migration runtime identity changed at seq 108 (0108_loose_puppet_master.sql)`
失败关闭——app 起不来,而且重装官方版也救不回:判定依据是 userData 里的数据库与
migration-runtime manifest,不属于安装包。

修法(只认登记在册、内容指纹完全一致的重编号,其余仍失败关闭):
- migrationRunner: 新增 KNOWN_RENUMBERED_APPLIED_MIGRATIONS 登记表与
  resolveCanonicalAppliedIdentity;已落库旧身份能解析到 canonical 时重写 manifest,
  并把它腾出的旧 seq 一并销账;「canonical 未执行」的缺条目检查只查到已落库前缀为止。
- 0108 重放守卫:重编号血统的 bot_direct_messages 缺 sender_name/recipient_name 时,
  在该迁移事务内把表收敛回 0108 执行后的等价结构(列序/索引对齐,先自查无外部外键引用)。
- migrate: up-to-date 与 replay 两条启动路径都调用 reconcileRenumberedAppliedSchema,
  保证「旧 checkout 血统」的 schema 收敛不会被 pending 为空短路掉。

测试:migrationCompatibility / migrationReplay 新增重编号修复与重放守卫用例;
四个引用 migrationRunner/migrate 的测试文件 39 通过,tsc 通过。

Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
(cherry picked from commit 194299a)
(cherry picked from commit d697139)
zyjisdog added a commit to zyjisdog/cindy that referenced this pull request Sep 19, 2026
Upstream-PR: makecindy#4598
Upstream-PR-Head: 6e5c18d
Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
zyjisdog added a commit to zyjisdog/cindy that referenced this pull request Sep 19, 2026
本地构建曾把 makecindy#4598 的「任务级上下文窗口档位」迁移落成 0108_loose_puppet_master.sql;
之后该分支合入上游时,主干已在 0108 放了 bot 私聊迁移(0108_lowly_scarlet_witch.sql),
同一 schema 意图被重编号到 0110_green_unus.sql。于是「用旧包升级过、又换新包」的库会在
prepareMigrationRuntimeManifest 处以
`applied migration runtime identity changed at seq 108 (0108_loose_puppet_master.sql)`
失败关闭——app 起不来,而且重装官方版也救不回:判定依据是 userData 里的数据库与
migration-runtime manifest,不属于安装包。

修法(只认登记在册、内容指纹完全一致的重编号,其余仍失败关闭):
- migrationRunner: 新增 KNOWN_RENUMBERED_APPLIED_MIGRATIONS 登记表与
  resolveCanonicalAppliedIdentity;已落库旧身份能解析到 canonical 时重写 manifest,
  并把它腾出的旧 seq 一并销账;「canonical 未执行」的缺条目检查只查到已落库前缀为止。
- 0108 重放守卫:重编号血统的 bot_direct_messages 缺 sender_name/recipient_name 时,
  在该迁移事务内把表收敛回 0108 执行后的等价结构(列序/索引对齐,先自查无外部外键引用)。
- migrate: up-to-date 与 replay 两条启动路径都调用 reconcileRenumberedAppliedSchema,
  保证「旧 checkout 血统」的 schema 收敛不会被 pending 为空短路掉。

测试:migrationCompatibility / migrationReplay 新增重编号修复与重放守卫用例;
四个引用 migrationRunner/migrate 的测试文件 39 通过,tsc 通过。

Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
(cherry picked from commit 194299a)
(cherry picked from commit d697139)
@zyjisdog zyjisdog closed this Sep 19, 2026
@zyjisdog zyjisdog reopened this Sep 19, 2026
@zyjisdog

Copy link
Copy Markdown
Contributor Author

补充说明这次同步主干带来的迁移调整(不改功能语义,只改迁移身份与幂等形态):

1. 迁移号 0108 → 0110 → 最终 0114

上游在 v0.1.88 已发布 0110_abandoned_scarlet_witch / 0111 / 0112 / 0113,占掉了本功能此前顺延到的 0110 号。现在按 docs/dev-rules/database-and-migrations.md 的要求,以主干最新迁移链用 drizzle-kit 重新生成(没有手改文件名、journal 或 snapshot):本次生成 0114_blue_harrier.sql,journal 与 meta/0114_snapshot.json 均为 drizzle-kit 产物。

2. 迁移改成自带守卫的幂等形态

同一份规则要求「新迁移必须自带守卫」(SQLite 的 ALTER TABLE ADD COLUMN 没有 IF NOT EXISTS,直接写进 SQL 无法重放;仓库里 0075 / 0076 是既有范式)。所以 0114_blue_harrier.sql 只留 SELECT 1;,实际加列放在同名 companion drizzle/scripts/0114_blue_harrier.ts,用 PRAGMA table_info('sessions') 判断列是否已存在:

function run(db) {
  if (!hasColumn(db, 'sessions', 'context_window_budget')) {
    db.exec('ALTER TABLE `sessions` ADD `context_window_budget` integer');
  }
}

这一条不只是形式:任何已经跑过本分支早期构建的库都已经有这一列(此前那份迁移是无守卫的裸 ALTER),没有守卫的话重放会直接报 duplicate column 并阻断启动。新增回放用例 replays the guarded 0114 companion over an existing column as a no-op 覆盖这个路径。

3. 验证(head f80c5505)

  • pnpm --filter desktop db:validate:0000..0114 连续、journal 对齐、无 schema drift、companion 为 CommonJS;
  • pnpm --filter desktop test:migration-replay:12/12(含上面的守卫用例);
  • pnpm --filter desktop typecheck:通过;
  • 本功能 11 个测试文件 516 例、packages/device-link allowlist 49 例:全过;
  • pnpm test:runner:全绿(本机需要把 rustc 放进 PATH,属环境前置);
  • 相对上游 main 的差异仍只有本功能自己(53 文件 / +9252-43,含生成的 snapshot)。

@zyjisdog zyjisdog closed this Sep 21, 2026
@zyjisdog zyjisdog reopened this Sep 21, 2026
zyjisdog added a commit to zyjisdog/cindy that referenced this pull request Sep 21, 2026
Upstream-PR: makecindy#4598
Upstream-PR-Head: f80c550
Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
@zyjisdog

Copy link
Copy Markdown
Contributor Author

追加说明:任务窗口预算不再进数据库(f55652e36 / merge 26dd1d395)

按 需求方的风险分析 做了存储位置的调整:任务级窗口预算从会话列改为 main 侧偏好文件,本 PR 现在不含任何 migration。

为什么改:预算原本设计成 sessions.context_window_budget + 新迁移。那会改写迁移链身份 —— 库一旦记上本分支独有的迁移,任何不带该迁移的包(官方包)启动时会以 applied migration runtime identity changed at seq ... 拒绝启动,反向亦然。也就是说,用户会在「官方包」和「带本功能的包」之间永久二选一,而任务级窗口只是纯客户端偏好,不值得换一个不可逆的库状态。

现在怎么存:owner 隔离的 userData 下 session-context-budget-prefs.json({ budgets: { "<sessionId>": tokens } },null / 缺条目 = 跟随模型默认),与既有的「单模型上下文上限」同一套写入约定(临时文件 + 原子 rename、mtime 失效)。fork 时复制条目,硬删任务时清理;越界(< 1000 / > 1e8)与非整数显式拒绝。

行为没变:档位表、有效窗口收敛(min(任务预算 ?? 模型级上限, 模型级上限, 目录 contextWindowMax))、三引擎下发、切模按目标路由重新收敛、保存后应用(空闲关 handle / 回合中 pending)都不变;只是读取入口从 DB 换成偏好文件,chip 的权威边界响应新增 budget / budgetCustomized(本地由 main 算,远程由被控端算并回带)。

数据库回到上游:apps/desktop/drizzle/**、schema.ts、mapper.ts 与上游逐字节一致;pnpm --filter desktop db:validate 输出 0000..0113、no schema drift;迁移 replay 用例通过。因此同一条库可以在官方包与本分支包之间自由来回切换。

验证(本轮):pnpm test:unit:related 全绿(59 个 workspace 全 PASS,含 desktop unit 533.9s / test:runner 92.1s;其中 test:runner 第一次红是环境中 GNU tar 抢在 Windows tar 前(tar: Cannot connect to C: resolve failed),把 C:\Windows\System32 提到 PATH 前面即绿,与本改动无关);apps/desktop 与 @cindy/device-link 的 typecheck 通过;新增 sessionContextBudgetStore 单测(读写 / 外部编辑生效 / 越界拒绝 / fork 复制 / 删除清理)与边界契约用例(budget、budgetCustomized 归一化)。

@MagicLizi MagicLizi removed the touches:redline 改动碰到红线路径(updater / DB schema 等,review-pr 自动维护,仅展示) label Sep 21, 2026
zyjisdog added a commit to zyjisdog/cindy that referenced this pull request Sep 21, 2026
Upstream-PR: makecindy#4598
Upstream-PR-Head: 26dd1d3
Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
@zyjisdog

Copy link
Copy Markdown
Contributor Author

@greptileai review

存储位置刚从「新增会话列 + 迁移 0114」改成「main 侧偏好文件(session-context-budget-prefs.json)」,drizzle/schema/mapper 已全部回到上游(db:validate = 0000..0113、no schema drift)。请重点看:偏好文件的读写/清理生命周期(fork 复制、硬删 prune、越界拒绝、外部编辑失效)、maker:get-context-window-bounds 新增的 budget/budgetCustomized 契约(本地 main 算、远程被控端算),以及 chip 从「会话快照取值」改成「等权威边界回来」后的乐观更新与失败回滚。

Comment thread apps/desktop/src/main/maker-ipc/register.ts Outdated
Greptile P1(2026-10-24):已有待处理的模型/来源切换时,改预算走 pendingTarget
分支只补 forceSessionRebuild 就返回,没有登记重放意图。那条 pending 随后被
「重选当前模型」清掉(SET_MODEL 成功路径 agentSwitchPending.clear),预算就
再也没有应用点,任务继续用旧窗口。

- pendingTarget 合并分支补 pendingSessionContextWindowBudgetReconciles.add;
- 「有效窗口没变」「已应用」两个出口清掉残留意图(否则每条消息都白跑一次对账);
- 切片扩到包含 applier,新增回归用例「已有切换 → 改预算 → 重选模型 → 发送」
  断言:合并不重建(不记 dedup)但意图留下(反向验证:去掉 add 立即变红)。

285 例 + tsc + hygiene 全过。

Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>

@zqchris zqchris left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

这次补的是合并进待处理切换那条路:改预算并到已有的模型/来源切换里时,也登记重放意图,这样那条切换被「重选当前模型」清掉后,发送边界还能把预算补上。另外「已应用」「有效窗口没变」两个出口顺手清掉残留意图,避免每条消息白跑一次对账。回归用例也覆盖了。批准,等 CI 全绿。

@zyjisdog

Copy link
Copy Markdown
Contributor Author

@greptileai review

Comment thread apps/desktop/src/main/maker-ipc/register.ts Outdated
Greptile P1(2026-10-24):previous 只是「上一个保存值」,不是活实例当前的
窗口。实例 300K、模型级上限 500K 时,回合中先存 500K 再存 600K——第二次两个
保存值都收敛到 500K,判定「没变」,但实例仍是 300K。此前在这个出口清掉重放
意图,随后重选模型取消 pending,预算就永久不生效。

意图改为只在三种终态清除:真正 applied、记账值等于偏好值、实例已关。
新增用例复现该两次保存序列(反向验证:加回 delete 立即变红)。

Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>

@zqchris zqchris left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

这次去掉了「有效窗口判为没变」出口清意图的那一行:previous 只是上一个保存值、不代表活实例当前窗口,两次保存收敛到同一上限时确实会误判,清掉就会让预算永久不生效。现在意图只在真正 applied、记账值等于偏好值、实例已关这三种终态清除,留着最多是发送边界多做一次对账,代价很小。复现两次保存序列的用例也补上了。批准,等 CI 全绿。

GLM-5.3 独立对抗审查发现两条:

P1:预算重放只挂在直发(IM/Goal/定时任务)边界。回合中改预算登记意图后,
用户在模型选择器里点选会清掉那条 pending 凭证切换,随后从桌面 UI 发消息走
createMakerSendTransaction → applyPendingAgentSwitch(只调
applyPendingAgentSwitchIfIdle,不重放),预算永久不生效——最普通的操作路径
反而失守。抽出 replayPendingSessionContextWindowBudgetUnderLock(锁内,调用
方持 send 锁),直发 holder 与 UI 发送事务两处共用。

P3:偏好文件不可读时 store 拒绝写,两处写入的失败语义互相矛盾——
persistSessionFields 把预算写放在行更新之前(失败带走整包字段);
updateSessionInDb 放在行更新+广播之后且无兜底(IPC 报错但改名已落库)。
现在都降级为「预算未保存」的 warn:persistSessionFields 把写挪到行更新之后
并用 budgetWritten 门控 apply;updateSessionInDb 收进 try/catch。

用例:重放门控改成执行式(原先是源码字符串断言,GLM 指出挡不住回归)+
「UI 发送事务确实重放」;新增「store 拒绝写时行更新照旧」(反向验证两条都
变红)。331 例 + tsc + hygiene 全过。

Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
@zyjisdog

Copy link
Copy Markdown
Contributor Author

另做了一轮独立对抗审查(不改代码逻辑,专门找并发/时序/生命周期/失败路径/假绿),报出 1 条 P1 + 2 条 P3,全部核实并处置(287d52b4d7):

P1 — 预算重放只挂在直发边界,桌面 UI 发送路径没有
我此前修 Greptile P1 时,只把重放加在直发(IM / Goal / 定时任务)的 pendingAgentSwitchApplyHolder 里。而桌面 UI 发消息走 createMakerSendTransaction → applyPendingAgentSwitch,那里只调 applyPendingAgentSwitchIfIdle。于是这条最普通的路径失守:回合中改预算(登记 deferred 意图)→ 在模型选择器里点选(clearPendingCredentialSwitchForSession 清掉那条 pending)→ 从界面发消息(无重放)→ 预算永久不生效。

修法:抽出 replayPendingSessionContextWindowBudgetUnderLock(锁内,调用方持 send 锁),直发 holder 与 UI 发送事务两处共用同一实现,避免再出现「只补了一处边界」。

P3 — 偏好文件不可读时的失败语义互相矛盾
store 在文件损坏/超限时拒绝写(保留坏文件给人工修)。persistSessionFields 把预算写放在行更新之前(失败会带走同一 patch 的其它字段,如改名);updateSessionInDb 放在行更新+广播之后且无兜底(IPC 报错但改名已落库,UI 回滚后看着像改名丢了)。现在都降级为「预算未保存」的 warn:前者把写挪到行更新之后并用 budgetWritten 门控后续 apply,后者收进 try/catch。

P3 — 测试假绿
原先「发送边界重放」只有一条源码字符串断言(expect(boundary).toContain(...)),删掉重放也不会红——这正是 P1 能溜过去的原因。已改为执行真实 replay 函数的参数化用例(意图无/有 → 对账调用 0/1 次),另加一条断言 UI 发送事务确实重放。反向验证:去掉任一处修复,对应用例立即变红。

未采纳的一条:worker 唤醒注入仍由顺序断言覆盖。该注入函数本身有 353 行行为用例(modelContextSettings.sessionBudget.test.ts),唤醒路径只断言「调用了它、顺序正确」,判定为可接受,不再堆重复用例。

CI 重新跑中。

@zyjisdog

Copy link
Copy Markdown
Contributor Author

@greptileai review

@zqchris zqchris left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

这次两处都成立:把发送边界的预算重放抽成 replayPendingSessionContextWindowBudgetUnderLock,桌面 UI 发送事务的 applyPendingAgentSwitch 也走一遍,补上了「回合中改预算、选择器点选清掉 pending、从界面发消息」这条最常见路径;偏好文件写失败改成在行更新之后、降级为 warn 并用 budgetWritten 门控 apply,不再连累同一个 patch 里的改名等字段。重放门控的用例改成真正执行函数,也比断言源码文本靠谱。批准。现在标签还挂着 ci-failed,请确认这轮 CI 跑完全绿再等合入。

Comment thread apps/desktop/src/main/localDb/ipc/sessions.ts
Greptile P1(2026-10-24)指出我上一条降级改过头了:maker:set-context-window-budget
只提交预算字段,偏好文件损坏/超限时 store 拒绝写,新加的 catch 把错误吞掉 ——
预算没保存、新窗口也没应用,请求却正常返回,用户想缩小窗口省钱时仍按旧窗口跑。

按 patch 形态分流:
- 纯预算 patch(除 contextWindowBudget 外无其它字段)→ 抛出,让 IPC 明确失败;
- 混合 patch → 其它字段已落库,保留降级,但把未写入的 contextWindowBudget 从
  broadcast 里剔除,避免 UI 显示一个没存下去的值。
persistSessionFields 与 updateSessionInDb 两条入口都按这个口径处理。

用例:新增「纯预算请求在 store 拒绝写时 rejects」,混合那条补断言广播值不被当成
已保存。216 例 + tsc + hygiene 全过。

Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>

@zqchris zqchris left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

这次收得对:纯预算请求(maker:set-context-window-budget 就是这种)只有这一个意图,store 拒绝写时就该让 IPC 明确失败,不能「看着成功、实际还是旧窗口」;混合 patch 保留降级,persistSessionFields 里也把没存下去的 contextWindowBudget 从广播剔掉了。新用例覆盖了纯预算 rejects。

小提醒(不卡):updateSessionInDb 的混合 patch 分支广播在写偏好之前就发了,提交说明说两条入口都剔除了广播值,实际这条没剔,失败时 UI 可能短暂显示没存下的值。后面顺手对齐就好。批准,CI 跑完全绿再等合入。

该用例直接切片 register.ts 的 applyPendingAgentSwitch 适配器执行,新增的
replayPendingSessionContextWindowBudgetUnderLock 需要显式注入(no-op,
用例只关心切换守卫)。

Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>

@zqchris zqchris left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

这次只动了 makerSendTransaction.test.ts:切片执行 applyPendingAgentSwitch 适配器时补上 replayPendingSessionContextWindowBudgetUnderLock 的 no-op 注入,跟上一条把预算重放挂到桌面发送事务的改动对齐,用例仍只验切换守卫,没问题。请保持 CI 跑到全绿再等合入。

@zyjisdog

Copy link
Copy Markdown
Contributor Author

@greptileai 的 P1(纯预算请求失败被吞)已处置(b755ee77fd),线程内已回复。

之后又补了一处:makerSendTransaction.test.ts 里有一条用例直接切片 register.ts 的 applyPendingAgentSwitch 适配器执行,我给那段加了预算重放后它需要显式注入(no-op,用例只关心切换守卫)——6e6c92a7b2。

CI 现在 18/18 全绿(Linux 1-4/4、Windows runner/unit 1-4/4、database、Git integration、hygiene 等),DCO 8 commits passed。

@greptile-apps

greptile-apps Bot commented Oct 24, 2026

Copy link
Copy Markdown

发现 1 条:

  • P1 — apps/desktop/src/main/localDb/ipc/sessions.ts:920:远程镜像预算写入缺少 owner-scope 复核。 persistSessionFields 在 await db.update(...) 后直接调用 writeSessionContextWindowBudget,并继续应用预算;而偏好文件路径按当下账号解析。若设备切账号发生在这次 await 期间,旧账号的镜像更新会写入新账号的预算文件(并可能对新 owner 的活会话执行应用)。与 updateSessionInDb 中已加的 isOwnerScopeCurrent(ownerScope) 守卫相比,这条镜像路径还没有在写偏好及应用前复核 owner scope。建议两处都仅在 scope 仍有效时执行。

另外,GitHub 当前 PR 元数据显示 mergeable_state: dirty / mergeable: false,且该 head 的 checks 状态接口返回 pending、total_count: 0;这与描述中的 18/18 绿 CI 不一致,合并前需确认是否需要 rebase 或重触发检查。

Greptile P1(2026-10-24):persistSessionFields 的预算写与 apply 都在
await db.update 之后,偏好文件按「当下」账号的 userData 解析——保存期间切账号
时,这条远程镜像更新会把旧账号任务的预算写进新账号的文件,甚至对新 owner 的
活会话执行应用。updateSessionInDb 早先已加 isOwnerScopeCurrent 守卫,镜像路径
漏了。

现在写偏好与 apply 都要求 scope 仍有效(同一函数内各查一次,O(1))。
新增用例「镜像落库在 owner 变化后不写偏好」(反向验证:去掉守卫立即变红)。

Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>

@zqchris zqchris left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

55216f6 看过:远程镜像路径 persistSessionFields 补上和 updateSessionInDb 同口径的账号边界守卫,写偏好和 apply 前都复核 owner scope,配了反向用例,成立。

现在 GitHub 显示和 main 有冲突(mergeable: dirty),CI 也是红的,麻烦 rebase/合一下 main、跑到全绿再等合。

Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>

# Conflicts:
#	apps/desktop/src/main/bootstrap-electron.ts
@zyjisdog

Copy link
Copy Markdown
Contributor Author

判定:成立,已修(55216f6e20)。

确认了:persistSessionFields(远程 set-* 镜像落库)在 await db.update(...) 之后才写偏好文件,而 writeSessionContextWindowBudget 的路径按「当下」账号的 userData 解析。保存期间切账号时,旧账号的镜像更新会写进新账号的 session-context-budget-prefs.json,并可能对新 owner 的活会话执行应用。updateSessionInDb 上一轮已加 isOwnerScopeCurrent(ownerScope) 守卫,镜像路径漏了。

修法:写偏好与 apply 都要求 scope 仍有效(同一函数内各查一次,O(1),apply 在 await 之后再复核一次)。用例:「镜像落库在 owner 变化后不写偏好」——反向验证,去掉守卫立即变红。

关于 mergeable: false:上游在评审期间前进(5bc6b6469f → e07a8abbc2),唯一的冲突在 bootstrap-electron.ts 的相邻 import 行。已 merge upstream/main(9e30a709e2)解为并集并逐处核对:两边新增都保留,我们的 applyContextWindowBudget 接线与上游的 pi-idle-release watcher 都在。相关测试 624 例 + Pi 55 例 + tsc + hygiene 全过,CI 已在新 head 上重跑。

@zqchris zqchris left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

9e30a70 只是把 main 合进来,冲突已解开:本 PR 相对 main 的改动还是原来那些(bootstrap / registerAll / sessions / maker-host / channels / register / preload / vite-env 的接线都在),没看到冲突标记,也没混进别的逻辑。重新批准,合并前以 CI 跑到全绿为准。

@zyjisdog

Copy link
Copy Markdown
Contributor Author

@greptileai review

Comment thread apps/desktop/src/main/__tests__/fork.test.ts Outdated
Greptile P2(2026-10-24):未登录时 ownerScopedUserDataPath 退到
app.getPath('temp'),而 mock 只重定向了 userData → 预算偏好落到固定的
/tmp/cindy-fork-test/temp,不在 afterEach 清理范围内,同进程用例会共享同一份
文件。现在 temp 也指向每例临时目录;顺便把 mkdtemp 改成 await(原先 .then()
不等待,用例可能在目录建好之前写偏好)。fork 89 例 + tsc + hygiene 全过。

Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>

@zqchris zqchris left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

a9c713f 只动了 fork.test.ts:未登录时 ownerScopedUserDataPath 会退到 app.getPath('temp'),现在 mock 把 temp 也指到每例临时目录,用例之间不再共享同一份偏好文件;mkdtemp 改成 await 也对,之前 .then() 不等,用例可能在目录建好前就写偏好。纯测试隔离,成立,批。合并前以 CI 全绿为准。

@zqchris zqchris left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

a9c713f 只动了 fork 测试:未登录态的 temp 路径也隔离到每例临时目录,mkdtemp 改成 await,修得对。重新批准,合并前以 CI 全绿为准。

@zyjisdog

Copy link
Copy Markdown
Contributor Author

@greptileai review

@MagicLizi

Copy link
Copy Markdown
Contributor

PR #4598 独立代码审查报告(heavy 档)

  • PR:feat(desktop): 任务级上下文窗口档位(内核) #4598 「feat(desktop): 任务级上下文窗口档位(内核)」
  • head a9c713f1a18a2f5ace8745d2c8db0d8ba7af8322 / base e07a8abbc26bb5e0da163ff8a83fb25bc9cfe1f2(main)/ diffHash a9a454b9…87975
  • 审查范围:41 文件 / +3056 行(内核:存储、边界解析、三引擎接入、fork/worker、device-link 命令面)

Findings

无 P0/P1。

P2 备忘(不阻断、不派 thread):

  • packages/maker-core/src/agents/pi/__tests__/pi-native-auto-compact.test.ts:764 新增用例访问
    readLatestPiSettings().compaction?.modelOverrides,超出该 helper 的返回类型
    { compaction?: { reserveTokens?: number } },tsc --noEmit(maker-core 的 build 脚本)会报
    TS2339。纯类型层缺口:vitest 不做类型检查、CI 只跑 desktop/mobile typecheck,运行时行为正确,
    55 例全过。建议顺手把 helper 返回类型补上 modelOverrides。
  • apps/desktop/src/main/maker-ipc/register.ts 在 EXPORT_SESSION_HTML 前多出一个多余空行(风格)。
  • apps/desktop/src/main/maker-host/model-context-settings.ts 中「模型级上限刻意不夹」的注释易误读:
    clampedByCatalog 阶段确实不按模型级上限夹,但下一行 tighterBudget 会取任务预算与模型级上限
    更紧者。代码与 PR 描述、docs/dev-rules/maker-core-and-agent-behavior.md 的
    min(任务预算 ?? 模型级上限, 模型级上限, 目录 contextWindowMax) 口径一致,仅注释表述需理顺。

已核验的既有 bot 意见落实(不重复开帖):

  • Greptile 2026-10-24 10:59 P1(sessions.ts:920 远程镜像写预算缺 owner-scope 复核):
    head 已修 —— persistSessionFields 写偏好/应用前 isOwnerScopeCurrent(ownerScope) 复核
    (55216f6e),updateSessionInDb 写偏好前同样重核;两条路径各有回归用例
    (sessionsUpdate.test.ts「does not mirror/write … after an owner change」)。
    Greptile 同条评论提到的 mergeable_state: dirty / checks pending 亦已消失(MERGEABLE/CLEAN,CI 全绿)。
  • Greptile P2(fork 用例未登录态 temp 路径未隔离):head a9c713f1 已修(每例独立临时目录)。
  • 23 条历史 review thread(Greptile P1/P2 各轮)全部 isResolved=true,与最终 diff 逐条比对无回归。

Rule coverage

规则 结论
AGENTS.md / docs/dev-rules/development-workflow.md 单一目的(任务级窗口档位内核);PR 描述、diff、测试一致;DCO 由 git commit -s 流程承载(PR 有 DCO 签名要求,检查以 GitHub DCO check 为准);P0/P1 口径按该文档执行
docs/dev-rules/electron-security-and-process-boundaries.md 新增两个 IPC handler(maker:set-context-window-budget / maker:get-context-window-bounds)均做 sender 校验:本地走 assertTrustedAppRendererEvent,device-link 调用走 isDeviceLinkInvoke() 放行(受 remoteControlEnabled + revoke + allowlist 约束);参数逐项校验、越界显式拒绝而非静默收敛;写路径复用唯一写入链路 updateSessionInDb,无平行写入口
docs/dev-rules/architecture-invariants.md 共享契约放 apps/desktop/src/shared/*,main/renderer/IPC 类型单向引用;maker-core 只新增可选 start option / setModel opt,未反向依赖 desktop
docs/dev-rules/credentials-and-local-storage.md 新增偏好文件 session-context-budget-prefs.json 走 ownerScopedUserDataPath(owner 隔离),store 复用 createOverrideSettingsFile(损坏文件保留、mtime 守卫、1MB 上限、16384 条目深防线);账号切换竞态两处写路径均复核 owner scope
docs/dev-rules/database-and-migrations.md 无 schema/迁移改动(全 diff 无 migration 文件,DB 停在官方基线);任务预算刻意不进 sessions 列,理由与规则中「迁移身份 fail-closed」一致
docs/dev-rules/maker-core-and-agent-behavior.md 三引擎接入与文档更新一致(预算=分母、压缩百分比=触发点正交;Pi 走 compaction.reserveTokens,CC/Codex 走 env + 重建标记)。该文档改写属 rules 确认门触发,已由维护者 zqchris Approve 放行
docs/dev-rules/pi-harness.md Pi 原生能力非退化:明确不调用非官方 set_compaction_reserve_tokens / refresh_models RPC,预算变化走官方 settings.json + 既有重建分支;未新增任何对 Pi 安装/更新/扩展的限制;新增测试反向断言不依赖非官方 RPC
docs/dev-rules/protocol-compatibility.md device-link allowlist 单向新增两个 channel;老被控端 CHANNEL_NOT_ALLOWED 降级(写=提示不支持保留原档位,读=退回「只允许收紧」);通用写入口 local-db:sessions:update 未放开(有测试钉住)
docs/dev-rules/remote-and-mobile-adaptation.md / configuration-and-overrides.md 远程写预算在被控端落自己的偏好并应用,与 maker:set-plan-mode 同档语义;设置存放/回滚口径与既有 override store 一致
DESIGN.md / 设计规范 本 PR 无组件/样式/布局/文案改动(renderer 仅 sessionService.ts 类型字段与 vite-env.d.ts IPC 声明);chip UI 与亮/暗截图在 UI PR #7011
docs/product-rules/review-product-direction.md 等产品规则 不涉及 /review、Bot 身份、Telegram;命名用「任务/对话」口径符合 task-and-conversation-naming(代码注释与文档均用「任务级」)

固定问题逐条:① 单一目的、描述一致 ✔;② 共享符号(resolveConfiguredContextWindow 新签名、bounds/budget 契约)调用方全部追踪(register.ts / model-context-settings / fork / session-storage / maker-host/index / runtimeSetModel / 三引擎 / preload / device-link)✔;③ 权限与用户数据安全、回滚=删偏好文件 ✔;④ 无新依赖、无数据外发、危险写法仅测试桩 ✔;⑤ main/IPC/协议/远程路径均有实际回归用例 ✔;⑥ 未把流程塞进 Core ✔;⑦ UI 证据随 #7011 ✔;⑧ 不涉及 mobile 原生/fingerprint ✔。

Verification

均在 PR head worktree 实跑(命令退出码如实记录):

  • node scripts/security-scan.mjs --base e07a8ab…(heavy 专项):依赖 audit 跳过(未新增/升级第三方依赖,无需 audit);semgrep(p/javascript + p/nodejs,仅相对 base 新增)0 条 finding。⚠️ 6 个文件解析错误(vite-env.d.ts、sessionsUpdate.test.ts、registerAll.ts、maker-host/index.ts、runtimeSetModel.test.ts、preload.ts)→ 该部分规则未覆盖,已对这 6 个文件的本 PR diff 逐行人工补读兜底。
  • 危险写法定性(signoff security 触发 4 处 dynamic-eval):makerEventHotPathOrdering.test.ts:1261/1310/1354/1402 的 new Function(...) 为测试内拼接本地模块源码片段执行(构造被测函数闭包),无网络调用、无凭证读取、无外发 —— 测试脚手架,非 P0。
  • desktop 定向单测 15 文件 847 例全过(fork / makerEventHotPathOrdering / makerSendToSessionOrdering / sessionRuntimeControlWiring / sessionsUpdate / modelContextSettings.sessionBudget / sessionContextBudgetStore 385 例;groupRuntimeRouteAuthorization / makerSendTransaction / orcaModelSelectionIntent / orcaWorkerResumeCleanup / runtimeSetModel / sessionContextWindow* 462 例)。
  • @cindy/maker-core pi-native-auto-compact.test.ts 55 例全过;@cindy/device-link allowlist.test.ts 54 例全过。
  • pnpm --filter desktop run typecheck(tsc --noEmit)exit 0;packages/device-link tsc --noEmit exit 0。
  • packages/maker-core tsc --noEmit(即其 build 脚本)exit 2:2 条来自 packages/lizi-mcps(本 PR 未触碰、base 即存在)的 ImportMeta.glob 报错,1 条为本 PR 新增测试的类型缺口(见 Findings P2)。该包无 typecheck script、CI 不跑它,vitest 全过;如实记录为未通过项,按 P2 处理。
  • node scripts/check-test-hygiene.mjs:PASS(363 files within baseline)。
  • git diff --check(base..head):无空白错误。
  • 未执行:pnpm test:unit 全量(本轮为定向验证,改动面已被上述 847+55+54 定向用例覆盖);UI 实机亮/暗目检(UI 在 feat(desktop): 任务级上下文窗口档位 UI:ContextWindowBudgetChip #7011)。

Intent alignment

  • 描述来源:PR body(2026-10-23 按维护者要求改写为「一拆三」说明)+ 讨论 issue 维护者确认:PR #4598 任务级上下文窗口档位(产品 / 规则 / 架构) #4601 + zqchris PR 评论(2026-10-23 05:51 要求拆分)。原目标:给单个任务加工作上下文窗口档位(容量分母),与全局压缩阈值百分比正交;contextWindow 语义继续来自目录,不改会话数据库。
  • 初始实现:4b4b9e032a766c447df5d97b24d13a371a046f5e(2026-10-23 17:52,parent 4e17ae5f,拆分后的第 1/3 部分内核)——已实际读取该提交 message 与范围(存储 store、边界解析、三引擎接入、fork/worker、device-link channel),与当前 diff 覆盖面一致。
  • 待合并 head:a9c713f1。初始到 head 的 13 个后续提交全部是审查修复/测试(zqchris review 四处、Greptile P1 逐条修复、发送边界预算重放三轮、账号边界复核、fork 测试隔离)+ 一次 upstream/main 同步合并,无功能扩范围。
原目标/初始行为 最终行为与影响 证据 变化依据
任务级窗口档位,不超过目录 contextWindowMax 不变:有效窗口=min(任务预算??模型级上限, 模型级上限, 目录 contextWindowMax) model-context-settings.ts resolveConfiguredContextWindow / tighterBudget —
初始:落库新列 sessions.context_window_budget(讨论 issue 初版口径) 改为 owner 隔离偏好文件 session-context-budget-prefs.json,无迁移 session-context-budget-store.ts 头注;diff 无 migration 文件 迁移会使旧包/官方包对同一库 fail-closed 启动,属实现载体替换、语义不变;zqchris 在变更后(2026-10-24 12:54)对当前 head Approve 放行
初始:Pi 预算热改(set_compaction_reserve_tokens) 改为官方 settings.json + 既有重建分支,显式拒绝非官方 RPC pi/index.ts switchModel 注释;pi-native-auto-compact.test.ts 反向断言 docs/dev-rules/pi-harness.md「只适配官方 Pi」红线,属同目标安全加固
单体(+5159 行,含 chip UI/底栏基建) 拆为内核(本 PR)/ UI #7011 / 基建 #7006 diff 无 ContextWindowBudgetChip/statusBarCards/focusTraversal/TodaySpendChip zqchris PR 评论明确要求拆分;范围收窄非偏离
菜单能否给高于默认窗口的档位(讨论行动项 1) 统一口径:档位基准=min(目录上限, 模型级上限),比例档 25/50/100%,能上能下但绝不越上限 sessionContextWindowBudget.ts buildContextWindowBudgetOptions + 文档更新 作者在 #4601 按实现统一了描述口径,dash-s-cushi 行动项 1 已闭环

结论:一致。核心目标(任务级窗口档位内核、目录上限不被越过、三引擎生效、fork/worker/远程一致口径)在最终 diff 中全部可核验;无删除/削弱/反转;讨论 issue 三项行动(语义统一、维护者审阅后放行、范围聚焦)均落实。存疑项无。

Overall

pass —— 没有 P0/P1。 heavy 档审查(含恶意代码与数据外发专项、security-scan)通过;23 条历史 thread 全部已解决且修复落实;维护门四类触发(product/security/rules/arch)由维护者 zqchris 对当前 head 的 GitHub Approve 放行;CI 双源全绿、无冲突、未落后 base、未命中受保护路径。建议按仓库惯例以 merge 方式合并。

警示(非阻断):机器人静默期超时放行 —— copilot-pull-request-reviewer / chatgpt-codex-connector 未对当前 head 表态,意见可能合并后到达(post-merge-sweep 兜底)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:large-diff 改动量较大(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) touches:rules 改动碰到规则 / 规范文档(review-pr 自动维护,仅展示) touches:security 改动碰到安全边界(review-pr 自动维护,仅展示)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants