gstack Pacing Updates 设计解读:如何把 30–50 次审查中断压缩到可接受范围
本篇解读 gstack 仓库中的设计文档 PACING_UPDATES_V0.md(状态:V1.1 计划,尚未实现),它回答了一个具体的工程问题:当一套 AI 审查流水线(/autoplan)在一次约 45 分钟的运行里向用户抛出 30–50 次 AskUserQuestion 提问时,如何通过"节奏(pacing)"改造把中断量压下来,同时不牺牲安全性(one-way door 决策必须全量呈现)。读完本文,你能理解该方案的问题建模、十个结构性缺陷、十项改造范围、可量化的验收标准,以及它如何与仓库中已有的 question-log、问题注册表、one-way 分类器等基础设施对接。
1. 问题来源:两种"疲劳",两种解法
设计文档的开篇把非技术用户阅读 gstack 审查输出时的疲劳归结为两个独立来源:
- 术语密度(Jargon density)——技术术语出现时没有解释。这一半由 V1 计划(ELI10 写作标准)解决,对应 PLAN_TUNING_V1.md 中的写作风格规范(术语首用注释、结果导向措辞、短句)。
- 中断量(Interruption volume)——
/autoplan依次运行 4 个阶段(CEO + Design + Eng + DX),每个阶段触发 5–10 次AskUserQuestion提问,全链路约 30–50 次,持续约 45 分钟。文档给出的关键经验值是:非技术用户在约 10–15 次中断后就开始"走神"。这一半正是本文(V1.1)的主题。
文档用一句话点明方案边界:"Translation alone doesn't fix interruption volume. A translated interruption is still an interruption."(光做翻译修不了中断量,被翻译过的问题依然是问题。)因此修复必须改变"发现何时浮出水面"(WHEN findings surface),而不仅是"措辞怎么写"(HOW they're worded)。
这与 autoplan/SKILL.md 中的真实阶段结构相互印证:Phase 0.5 预检后,Phase 1(CEO,必跑)、Phase 2(Design,仅当检测到 UI 范围)、Phase 3(Eng,必跑)、Phase 3.5(DX,仅当检测到开发者向范围),每个阶段都以 STOP 标记开头,要求先 Read 对应 sections/*-phase.md 再执行,阶段之间"Each phase MUST complete fully before the next begins"。每个阶段内部的 STOP/AskUserQuestion 序列是硬编码在技能模板里的,这正是后文"结构性缺陷 #4"的由来。
2. 为什么被从 V1 中拆出来:10 个结构性缺陷
Pacing 工作流最初是 V1 计划的一部分(在 PLAN_TUNING_V1.md 的"Revision 3"中被提出:给发现排序、自动接受 two-way door、每阶段最多 3 次提问、Silent Decisions 块、flip <id> 命令)。第三轮 Eng Review 加第二轮 Codex Review 暴露出 10 个无法靠"改计划文字"修复的缺口,文档因此被整体拆出,进入独立的 V1.1 设计轮次。这 10 个缺口可以归为五类:
(a)状态模型缺失(#1、#5)
- Pacing 需要"每阶段状态":哪些发现已浮出、哪些被自动接受、哪些用户还能翻回。V1 只有"每次技能调用"级别的状态(用于 glossing),没有承载每阶段 pacing 记忆的后端存储。
- "回复
flip <id>可更改"原本只是一句散文承诺:没有命令解析器、没有状态存储、没有重放行为。一旦对话被压缩、Silent Decisions 块滑出上下文,原始决策就丢了。
(b)观测基础设施缺字段(#2)
- 静默 Eng 审查 #8 希望在"单阶段内提问超过 3 次"时告警,但 V0 的
question-log.jsonl没有phase字段;V1 声称"无需 schema 变更"与这个强制目标自相矛盾。仓库中 bin/gstack-question-log 的现行 schema 确实只有skill / question_id / question_summary / category / door_type / options_count / user_choice / recommended / followed_recommendation / session_id / ts / source等字段——没有phase,证实了该缺口。
(c)注册表覆盖不了动态发现(#3)
- scripts/question-registry.ts 的注册表覆盖的是"问题"(在技能定义时静态注册,约 30–50 个常见类别,one-way door 覆盖率要求 100%)。而审查发现(review findings)是运行时动态生成的,agent 会随手生成
{skill}-{slug}形式的临时 id。靠注册表做door_type: one-way强制执行,对 ad-hoc 发现无能为力——"agent 审查中途生成的一-way 安全性无法强制执行"。
(d)散文规则无法反转既有控制流(#4)
- V1 打算在 preamble 散文里加一条"先排序再提问"的规则。但现有技能模板(如
plan-eng-review)是按小节硬编码 STOP/AskUserQuestion 序列的;preamble 里的一句散文规则无法可靠覆盖模板中每一节的 STOP。文档的结论很明确:"The behavioral change is sequencing, not prompt wording."(行为改变在于执行顺序,不是提示词措辞。)
(e)边界中断与未校准的参数(#6、#7、#8、#9、#10)
- 升级后的迁移提示(提供恢复 V0 散文)本身算一次中断,会挤占 V1.1 想压缩的预算;首跑的 lake intro、telemetry、proactive、routing 注入等 meta-prompt 也都发生在"第一个真实技能运行之前",同样要计入。
- 排序公式从未用真实数据校准:V1 先后考虑过
product 0-8(被证明取值分布是{0,1,2,4,8},公式失效)和sum 0-6加阈值 ≥4,但都没对照过真实发现分布。 - "每个 one-way door 都必须浮出"与"每阶段最多 3 次"两条规则同时存在却未声明优先级,逻辑上矛盾。
- 验证值未定义:Silent Decisions 块的 "≥ N 条" 中 N 从未给值,吞吐量 JSON 的
active: true字段也无定义。
3. V1.1 的十项范围
文档的 Scope 部分给出 10 项具体改造,逐项对应上述缺口:
- 定义会话状态模型——per-skill-invocation / per-phase / per-conversation 三选一;后端存储预计为
~/.gstack/sessions/<session_id>/pacing-state.json,记录每阶段"已浮出 vs 自动接受"的发现清单;清理 TTL 与 preamble 中既有的会话跟踪(120 分钟,见 plan-tune/SKILL.md 的 preamble 中find ~/.gstack/sessions -mmin +120逻辑)保持一致。 - question-log schema 增加
phase字段——把每次 AskUserQuestion 归入其来源阶段(CEO / Design / Eng / DX / other);存量条目默认"unknown",非破坏性扩展。 - 扩展注册表对动态发现的覆盖,两个候选方案(CEO review 时二选一):
- (a) 拓宽
scripts/question-registry.ts支持运行时注册(ad-hoc id 也要被记录并分类); - (b) 新增二级运行时分类器
scripts/finding-classifier.ts,用模式匹配把发现文本映射到风险层级。
- (a) 拓宽
- 把 pacing 从 preamble 散文移入技能模板控制流——更新每个审查技能模板,使其按显式序列执行:(i) 阶段内部先跑完,(ii) 用
gstack-pacing-rank二进制对发现排序,(iii) 最多发出 3 个 AskUserQuestion,(iv) 其余打包为 Silent Decisions 块。这不是 preamble 规则,而是模板中的显式执行顺序。 - 实现 flip 机制——新二进制
bin/gstack-flip-decision:从用户消息解析flip <id>,在 pacing-state.json 中查原始决策,重新展开为一个显式 AskUserQuestion,用户新选择持久化。 - 迁移提示的预算裁定——一次性迁移提示豁免于每阶段中断预算,理由:它们在审查阶段开始之前触发,而不是期间。
- 首跑 preamble 审计——逐个审计 lake intro / telemetry / proactive / routing 注入:"对首次用户是承重件,还是可延后?"文档预判的结果是:除 lake intro 外全部压到第 2 个会话之后,其余通过用户自愿调用的
/plan-tune first-run提供。 - 排序阈值校准——V0 的 question-log 已在运行且有历史数据,先测量近期 CEO + Eng + DX + Design 审查中
severity × irreversibility × user-decision-matters的真实分布,再定阈值。目标:约 20% 的发现浮出,约 80% 自动接受。 - 显式规则:one-way door 不设上限——硬编码进技能模板散文:"one-way doors surface regardless of phase interruption budget";two-way 发现每阶段上限 3 个。
- 给出具体验证值——定义 Silent Decisions 的 N(例如"非平凡计划预期 ≥ 5 条"),并给吞吐量 JSON 定义具体字段名。
4. 与仓库现有基础设施的对接(源码佐证)
设计文档不是凭空立论,其每一项都与仓库中已存在的机制衔接。以下几处源码可以让"锦上添花"部分落到实处。
4.1 问题日志:中断量的数据底座
bin/gstack-question-log 是 append-only 的 JSONL 写入器,落盘到 $GSTACK_HOME/projects/<SLUG>/question-log.jsonl。它对每个事件做严格校验:skill 必须 kebab-case;question_summary 限 200 字符且经 hasInjection()(共享自 lib/jsonl-store.ts 的审计模式列表)做注入防御;user_choice 限 64 字符;自动计算 followed_recommendation(比较前会剥掉双方尾部的 (Recommended) 标记)。它还支持 source 字段区分写入方(agent / hook / auto-decided 等),并对 source:tool_use_id 组合做 100 行窗口去重。写入后以 fire-and-forget 方式触发 gstack-developer-profile --derive 维持推断维度最新。
V1.1 的"每阶段可观测性"(/plan-tune 能显示任意会话的每阶段 AskUserQuestion 计数)正是建立在这条数据流之上——只需补一个 phase 字段。文档 #2 指出的矛盾在于:V1 声称"无 schema 变更",而告警目标恰恰依赖该字段。
4.2 问题注册表与 door_type:one-way 安全的主闸门
scripts/question-registry.ts 中每个注册项都声明 door_type: 'one-way' | 'two-way',注释规则是:one-way 用于破坏性操作、架构/数据模型分叉、超 1 天 CC 工作量的范围扩张、安全合规选择,"ALWAYS asked regardless of user preference";two-way 可被显式用户偏好自动决策。文件头注释说明注册表是 /plan-tune 的底座:question-log 用它打标、question-preferences.json 以它为键、心理画像信号映射(scripts/psychographic-signals.ts)以 (id, user_choice) 查维度增量。
Pacing 方案的排序前提就是这套 door_type 分类:预算优先花在最难逆转的决策上(见第 6 节的 fork 合并决策),two-way 发现才允许进"自动接受"通道。
4.3 双层 one-way 防线:注册表 + 关键词兜底
scripts/one-way-doors.ts 是"第二道防线",classifyQuestion() 的判定顺序在文件头注释中写得很清楚:
- 按
question_id查注册表,命中则直接用注册表的door_type(reason:registry); - 未命中则查技能类别兜底——
cso:approval与land-and-deploy:approval组合恒为 one-way; - 再对
question_summary做破坏性关键词正则匹配(rm -rf、force push、git reset --hard、drop table、terraform destroy、rollback、凭据 revoke/reset/rotate 等,reason:keyword); - 无任何证据时默认 two-way。
文件头特别引用了 V1 设计文档 Decision C 的结论:"散文解析太弱,不能当主闸门——措辞会变;注册表才是主闸门,这里只是未编目问题的兜底。" 这一分层结构与 V1.1 范围 #3 中方案 (b)(运行时 finding-classifier.ts 模式匹配器)在方法论上同源:动态发现也需要"先查注册表、再用模式匹配兜底、保守倾向多问一句"的次序。
4.4 用户偏好检查:AUTO_DECIDE 通道已经存在
bin/gstack-question-preference 提供 --check <id>,输出三态:ASK_NORMALLY / AUTO_DECIDE / ASK_ONLY_ONE_WAY;偏好值只能是 always-ask / never-ask / ask-only-for-one-way,且对注册表 one-way id 拒绝写入 never-ask("always-ask 在 one-way id 上没问题,因为它与安全覆盖一致")。autoplan/SKILL.md 中每个提问前的流程是:从注册表或 {skill}-{slug} 选 question_id,然后管道调用 gstack-question-preference --check "<id>" --summary-stdin(摘要走 stdin 喂给 one-way 关键词网);AUTO_DECIDE 意味着选推荐项并注明 "Auto-decided [summary] → [option] (your preference). Change with /plan-tune."。
这正是 V1.1 要"提速"的既有管道:现状是逐题询问偏好,V1.1 要在阶段维度上批量做"排序 + 自动接受 + Silent Decisions 块",并保证 one-way 恒问。
4.5 模板硬编码 STOP:为何散文规则失效
autoplan/SKILL.md 展示了缺口 #4 所指的具体形态:每个阶段以 **STOP.** Before starting Phase N ... Read sections/<phase>.md and execute it 的模板指令开头,且"NEVER run phases in parallel — each builds on the previous"。这意味着"先内部跑完一个阶段、再统一提问"的行为改变,必须落在各阶段模板的执行序列上(范围 #4 的第 (ii)(iii)(iv) 步),而不是加一句 preamble 散文。
5. 验收标准:可重跑、可计数的定义
文档的 Acceptance criteria 全部是可测量的:
- 中断计数:Louise(或同等非技术协作者)在一份与 V0-baseline 相当的计划上端到端重跑
/autoplan,AskUserQuestion 次数 ≤ V0 基线的 50%(V1 负责捕获基线转录供 V1.1 校准)。 - one-way 覆盖:100% 安全关键决策(
door_type: one-way或被分类器标记的动态发现)以完整技术细节逐条浮出,不设上限。 - Flip 往返:用户输入
flip test-coverage-bookclub-form,原自动接受决策重新展开为 AskUserQuestion;用户新选择持久化进 Silent Decisions 块(或若翻回"显式浮出"则从块中移除)。 - 每阶段可观测性:
/plan-tune可读取 question-log.jsonl 的新phase字段,显示任意会话的每阶段 AskUserQuestion 计数。 - 首跑削减:新用户第一个真实技能运行前看到的 meta-prompt ≤ 1 个(仅 lake intro),对比 V1 的 4 个(lake + telemetry + proactive + routing)。
- 人工重跑:Louise 与 Garry 独立定性评审,模式同 V1。
6. 对 V1 的依赖与明确不碰的东西
V1.1 构建在 V1 的基础设施之上:explain_level 配置键与 preamble 回显模式(V1 的 A4 项)、术语表 + 写作风格节(V1.1 的中断措辞本身要遵守 ELI10 规则)、V0 休眠负向测试(V1.1 同样不能唤醒 5D 心理画像机器)、以及 V1 捕获的 Louise 转录(验收校准基线)。文档同时声明 V1.1 不依赖任何 V2 项(E1 substrate wiring、narrative/vibe 等)。
"NOT touched in V1.1" 一节列出的 V2 延后项包括:困惑信号检测、5D 心理画像驱动的技能自适应(V0 E1)、/plan-tune narrative + /plan-tune vibe(V0 E3)、per-skill 或 per-topic 的 explain 级别、团队画像、基于 AST 的"已交付功能"指标。
7. Fork 合并:链级(chain-scoped)预算记账
文档末尾的"Fold-in from fork port wave 2 (2026-08-14)"记录了与 time-attack/gstack fork 的取舍:该 fork 从互补轴攻击同一问题——用构建规模分类(session/hobby/project/product/venture)决定机器体量,并引入全链提问预算。2026-08-14 CEO review 批准的合并决策是:只吸收 fork 的记账判断,不吸收其数值常量。具体规则四条:
- 预算是链作用域的:链式审查从剩余预算中扣减,绝不重置;
- 阶段交接时携带"questions-already-spent"(已花费的提问数);
- 审批/变更门(approval/mutation gates)永不计入预算;
- 预算优先花在最难逆转的决策上。
文档明确拒绝采纳 fork 的 5/8/12 数值常量——因为 fork 自己后来用"零默认的自主性拨盘"取代了它们。分工被表述为:"Scale sizes the machinery and sets the budget; pacing (this doc) ranks what the budget is spent on."(规模决定机器体量并设定预算;pacing 决定预算花在哪。)
8. 评审计划与文档定位
评审计划本身也体现了 gstack 的审查文化:预工作是从当前 V0 数据捕获真实 question-log 分布,作为范围 #8 的校准输入;CEO review 要求挑战前提("pacing 是对的药吗,还是干脆把 4 个阶段合并成一次统一审查?"),scope 模式预判为 SELECTIVE EXPANSION;Codex 独立过一遍,重点盯范围 #4 的控制流改动(V1 在这里翻过车);DX review 专注 flip 机制——flip <id> 是否可发现、命令语法是否自然、错误路径是否清晰;Eng review 预期多轮。
综合来看,PACING_UPDATES_V0.md 的价值不在任何单条技术点,而在于它示范了 AI 驱动的开发工具如何量化"人机中断成本":以 bin/gstack-question-log 的 JSONL 流水为数据底座,以 scripts/question-registry.ts 的 door_type 分类为安全不变式,以 scripts/one-way-doors.ts 的双层判定为兜底防线,再叠加"每阶段 ≤3、one-way 不设上限、~20% 浮出 / ~80% 自动接受"的量化目标与可重跑的验收标准。若你正在设计多阶段 LLM 审查流水线,这套"中断预算 + 门型分类 + 决策可翻转"的组合,是一个可以直接对号参考的工程范式。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00