Repository navigation
v0.2.7
TeamFlow v0.2.7
Release — 「澄清闸门 + PRD 确认单落地 + 机器契约彻底离开人类可读通道」版本(43 笔新提交 / 36 个文件 / +3485 −277 行,v0.2.6..HEAD 全量对比)。无破坏性:teamflow_start 的参数对象是 additionalProperties: true,本版摘出工具 schema 的两个字段(needConfirm / clarifyStrength)即使被传入也只被忽略、不会报错;journal / 任务夹契约 / teamflow_* 其余参数全部向后兼容。
中文
⬆️ 升级要点
- 本版主线三条:① 澄清闸门 + PRD 确认单(ADR-0010 / ADR-0011,最大一块);② resume / 断点系列修复(四处,其中两处是「机制上听起来对、实际全错」的伪代理判据);③ 机器契约彻底离开人类可读通道(state 块与蓝图块双双改走独立文件)。
- 产品路径改由内容驱动,不再靠开关:
needConfirm/clarifyStrength摘出公开工具 schema,改环境变量(TEAMFLOW_CONFIRM/TEAMFLOW_CLARIFY)。- 理由:一个「用户不会主动设、工具描述里也没说何时该设」的参数 = 功能不存在(用户原话:「用户又不知道这参数」)。
- 兼容性:参数对象
additionalProperties: true⇒ 老调用传入不报错,仅被忽略。
- PRD 确认单会主动暂停:PRD 里出现主观品味项(美术风格 / 交互形态 / 人设等)时,流水线停在 PRD 后等你批准,纯信息缺口不阻断(保住无人值守)。
- 升完重启
dsh --profile web(桌面版重启桌面应用)生效。
① 澄清闸门与 PRD 确认单(本版头条)
目的判据(用户拍板):不是「防返工」,而是让用户确认自己要实现的东西 —— 不能靠模型能力强度替代,因为产品主观性强的东西必须让用户自己创造迭代(否则「用户说实现贪吃蛇,就给他一个简单贪吃蛇」)。
- 确认单改「内容驱动」:旧实现用
needConfirm显式开关(用户得自己知道要敲它);现改为有主观项才停。配套:PRD 假设段从「只有信息不足」扩一维到主观决策项(7e2cf0a),openQuestions每条加kind: 'fact' | 'taste'(有taste才停)。 - AC 抽取三层(ADR-0011 C):结构化优先 → 正文兜底 → 来源必须自曝(空壳比空更糟)。真实语料逼出两条规则:故事表
| 用户故事 | AC-1: … |(AC 在第二列,只锚行首会漏 4/4)、区间引用行不得造垃圾条目。 - 确认单断点开放「回退重跑 PRD」(
4135abb):原先选项文案写着「我再更新确认单后开工」而后端明确拒绝supplement⇒ 假承诺(用户以为能改、点完才发现要么重开要么白跑)。现在断点开放回退重跑,判据落在内容上(stages除 prd 外无记录 ⇒ 作废面为零)。 - 澄清协议归 ctx 手册(
814472d):clarifyStrength从未影响过流水线(只选 ctx 文案变体)⇒ 整体移出PipelineOptions,默认档写进手册。判别式:若一个参数的唯一作用是在几个文案变体里挑一个,它就该是文案的默认值,不是参数。 - 开工前对齐也走 AUQ(
f96852d):手册补ask_user_question指令。 - 失效可见化(
a144138):澄清闸门失效时不再静默。 - 分诊侧:
blocker增guess软字段(模型自己的倾向,供用户快速作答)。
731fd42 —— journal.options 白名单漏了一个字段,导致 needConfirm 与 clarifyStrength 在真实路径下根本不生效,而测试全绿(因为 runScenario 直调 executePipeline,绕过了白名单)。⇒ 新增 PipelineOptions 字段时必须同时问「白名单收不收它」。
② resume / 断点系列修复(四处,两处是伪代理判据)
| 提交 | 事故 | 教训 |
|---|---|---|
9a97cd4 |
确认单暂停后无法续跑 | 无断点判据用了「已记录阶段全 done」这条伪代理 |
a298242 |
同一 run 内 state 从不刷新 | mergeStateBlock 返回新对象而调用点丢返回值 ⇒ 本 run 后续阶段看不见 extra.* |
9388cc6 |
断点定位第二层 | 「启用过但从未尝试」的阶段也应算断点 |
05f9fa3 |
零阶段 run 断点修正 | +续跑补录入口 |
1f1c4fa |
resume 文案把「从未尝试」说成「失败」 | !st || !st.done 同时含两种形态 ⇒ 两个数分开报 |
③ 机器契约彻底离开人类可读通道
一句话:机器契约(state 块 / 蓝图块)不再出现在任何用户会读的文本里 —— 既不在回复正文,也不在交付文档,连标记包裹都去掉。
b96b44e机器契约块不得出现在展示面(用户截图实锤:子任务卡把整段<!-- state -->{…}摊在用户眼前)。049961bstate 块改文件通道:机器契约不再走人类可读通道。9958cec蓝图改独立文件通道 + 截断抢救 + 原文落档(本版收口):- 蓝图从「
TECHNICAL.md末尾的块」改为logs/teamflow/<runId>/blueprint.json。Tech 文档是 user-facing deliverable,而蓝图块真机实测占其 31% 字符(5403/17583)。解析链三级回退:回复正文 → 独立文件 →TECHNICAL.md(历史通道)。 - 中转文件读完即删,清理与「通道是否命中」解耦 —— 模型「既回显又写文件」时不得漏删(否则可续跑终态不归档 ⇒ 永久残留)。
- 截断抢救
closeTruncated:实锤tf-mv3op3i2-0ok7nb,模型写了 5937 字符完整蓝图却缺最外层 1 个},既有repairBlueprintJson只治「提前闭合」救不了 ⇒ 12 个任务退化成 1 个整体开发。现按栈逆序补齐未闭合的{/[;⚠️ 仅当截断不在字符串内、且转义已收尾时才补 —— 断在字符串中间硬补会得到「语法合法但语义缺失」的对象,比直接失败更危险。 - 原文落档到
$DSH_HOME/teamflow/<ws>/blueprints/<runId>.json(无条件,成败都留)。此前蓝图三处去向都不留原文(render只在注入 prompt 那一刻、journal.blueprint只存{modules,tasks}、中转文件读完即删)⇒ 「模型到底设计成什么架构」无从复查。
- 蓝图从「
- 标记形态修正(
9958cec):<!-- state -->/<!-- blueprint -->是自闭合注释 ⇒ 渲染器把整条消化掉,紧随其后的 JSON 成为裸文本,在 Typora / VS Code 预览里直接显示给用户。open 去掉尾部-->;解析器(?:-->)?两种都认(兼容存量产物与模型旧习惯)。 - state 块改纯 JSON:文件是独立
.json,整份就是那个 JSON,标记纯属冗余(还会多出「写漏关闭标记」这类失败)。新增stateFromText(先按标记、失败再JSON.parse);extractStateBlock保持不动 —— pipeline 与dev.ts的回落是在自然语言回复里找块,标记仍是唯一锚。顺带删掉state.memory死字段。 9036446dev 任务标签:if (resume)分支原先无条件写「(补跑)」⇒ 哪怕 dev 一次都没跑过(确认单暂停后续跑)12 个任务也全被标成补跑,读起来像「上次跑挂了」。判据改为两路取或:断点在 dev 或更晚 / journal 里有该任务记录。
- 凡「用完即删」的中转物,必须留一条事后取证旁路(否则同类问题会变成「无法诊断」——实锤只能靠解压 dsh 会话轨迹、从
write的tool/call参数里抠出模型写了什么)。 - 测「函数正确」≠ 测「调用点接线正确」:
stateFromText单测全绿,而readStateBlockFile若没接上它,文件通道会静默返回 null。接线必须单独断言。
④ 其它修复
5ed35d2可自愈的文件防护门禁失败不再计入 env-unavailable(issue #15)。7bdf8a1「工具在这一层不适用」补入unknown tool+ 宿主文案漂移检查。ffb0c86蓝图tasks[]限定实现范围 —— 不许把 QA / 验收的活划成 dev 任务。b7072ab确认单改两步(先导总问单独一次);认可补录语义改成「固化进 PRD」。
⑤ 文档
- ADR-0010(澄清闸门)、ADR-0011(访谈协议 + PRD 确认门)、ADR-0006(蓝图形态与通道订正)。
docs/TODO.md重排为三段结构(真待办 / 观察中 / 已否决)。docs/devlog.md改按发布批次归并(非逐 commit)。
验证
- 门禁:
npm test全绿(含 golden corpus 的零 LLM 确定性回归)。 - 真机:本版三条主线各有实机 run 实证(
tf-mv3op3i2-0ok7nb/tf-mv3rdt0y-qmlxl3/tf-mv3upkft-2oggfu等)。 - ⏳ 截断抢救尚未被真机触发(单测用真机那个 5937 字符截断样本,另有部署产物验证;三次真机 run 的蓝图均为合法 JSON)——如实标注,不作「已验证」声明。
English
Release — "clarification gate + PRD confirm sheet + machine contracts fully out of human-readable channels" (43 commits / 36 files / +3485 −277 vs v0.2.6). No breaking changes: teamflow_start's parameter object is additionalProperties: true, so the two fields dropped from the tool schema (needConfirm / clarifyStrength) are silently ignored, never an error.
⬆️ Upgrade notes
- Three main threads: ① clarification gate + PRD confirm sheet (ADR-0010/0011); ② four resume / checkpoint fixes (two were "sounds right, actually wrong" proxy criteria); ③ machine contracts fully out of human-readable channels (both the state block and the blueprint block moved to dedicated files).
- Product paths are content-driven now, not switch-driven:
needConfirm/clarifyStrengthwere removed from the public tool schema in favour of env vars (TEAMFLOW_CONFIRM/TEAMFLOW_CLARIFY). Rationale: a parameter the user would never set, and whose description never says when to set it, is a feature that does not exist. - The PRD confirm sheet pauses on subjective items (art style / interaction / persona). Pure information gaps do not block, preserving unattended operation.
- Restart
dsh --profile web(or the desktop app) after upgrading.
① Clarification gate & PRD confirm sheet (headline)
The purpose is letting the user confirm what they are actually getting built — not "preventing rework". Model strength cannot substitute for it: highly subjective product decisions must be left to the user to iterate on.
- Content-driven confirm sheet: the old explicit
needConfirmswitch is gone; the pipeline stops only when a subjective item exists. The PRD assumption section gained a "subjective decisions" dimension, and eachopenQuestionsentry now carrieskind: 'fact' | 'taste'(onlytasteblocks). - Three-layer AC extraction: structured first → prose fallback → source must self-disclose. Two rules came from real corpora: the story table puts ACs in the second column; range-reference rows must not produce junk entries.
- The confirm-sheet checkpoint can now re-run the PRD: the previous UI text promised "I'll update the sheet then start", while the backend rejected
supplement— a false promise. Now the checkpoint supports going back. - Clarification protocol moved into the ctx manual:
clarifyStrengthnever affected the pipeline (it only picked a ctx wording variant) and was removed fromPipelineOptions. Rule of thumb: if a parameter's only job is to pick one of several wording variants, it belongs in the wording defaults, not in a parameter. - 分诊 gained a
guesssoft field on blockers.
journal.options whitelist missed one field, so needConfirm and clarifyStrength never took effect on the real path — while tests stayed green, because runScenario calls executePipeline directly and bypasses the whitelist.
② Resume / checkpoint fixes
| Commit | Incident | Lesson |
|---|---|---|
9a97cd4 |
Could not resume after a confirm-sheet pause | Checkpoint criterion used "all recorded stages done" — a proxy |
a298242 |
State never refreshed within a run | mergeStateBlock returns a new object; the call site dropped it ⇒ later stages never saw extra.* |
9388cc6 |
Checkpoint detection, second layer | "Enabled but never attempted" also counts as a checkpoint |
05f9fa3 |
Zero-stage run checkpoint fix | plus a resume backfill entry |
1f1c4fa |
Resume wording called "never attempted" a "failure" | the !st || !st.done predicate covers both shapes ⇒ report two numbers |
③ Machine contracts out of human-readable channels
Machine contracts (state block / blueprint block) no longer appear in any text a user reads — neither in the reply body nor in delivered documents, not even as wrapped markers.
b96b44eMachine-contract blocks must not appear on the presentation surface (user screenshot: a subtask card displayed the whole<!-- state -->{…}).049961bThe state block moved to a file channel.9958cecThe blueprint moved to a dedicated file, plus truncation rescue and raw-text archiving:logs/teamflow/<runId>/blueprint.json— the Tech document is a user-facing deliverable, and the blueprint block measured 31% of its characters (5403/17583) on a real run. Parse chain falls back three levels: reply body → dedicated file →TECHNICAL.md(legacy).- The transient file is deleted after reading, with cleanup decoupled from "was the channel hit" — a model that both echoes and writes must not leave the file behind (resumable terminal states are never archived ⇒ it would linger forever).
- Truncation rescue
closeTruncated: a real run wrote a 5937-character complete blueprint missing the outermost}, and the existingrepairBlueprintJson(which only handles premature closing) could not save it — 12 tasks collapsed into 1 whole-requirement task. Now unclosed{/[are closed in reverse stack order;⚠️ only when the truncation is not inside a string literal and escaping is complete — force-closing mid-string yields a "syntactically valid but semantically missing" object, worse than a clean failure. - Raw-text archiving to
$DSH_HOME/teamflow/<ws>/blueprints/<runId>.json(unconditional). Previously none of the blueprint's three destinations kept the raw text, so "what architecture did the model actually design" was unreviewable.
- Marker form fix:
<!-- state -->/<!-- blueprint -->are self-closing comments — renderers swallow the whole comment and the following JSON becomes bare text, shown directly to users in Typora / VS Code preview. The-->is dropped from the open marker; parsers accept both forms. - State block now pure JSON: no markers in the file at all. New
stateFromText(marker first, thenJSON.parse);extractStateBlockunchanged — the fallback path still searches natural-language replies, where markers remain the only anchor. 9036446dev task labels: theif (resume)branch unconditionally wrote "(rerun)" ⇒ even a run where dev never executed had all 12 tasks labelled as reruns, reading like "the last run crashed". The criterion is now a two-way OR.
- Anything transient that is deleted after use must keep an after-the-fact forensic path — otherwise the same class of problem becomes undiagnosable (in practice the only recovery was decompressing the dsh session trace and digging the model's
writetool/callarguments). - Testing that a function is correct ≠ testing that the call site is wired:
stateFromTextunit tests were green, whilereadStateBlockFilefailing to use it would make the file channel silently return null. Wiring needs its own assertion.
④ Other fixes
5ed35d2Self-healing file-guard failures no longer count as environment-unavailable (issue #15).7bdf8a1unknown tooladded to "this tool does not apply at this layer", plus a host-wording drift check.ffb0c86Blueprinttasks[]are scoped to implementation — QA/acceptance work must not be handed to dev tasks.b7072abConfirm sheet split into two steps.
⑤ Docs
- ADR-0010, ADR-0011, ADR-0006 (blueprint form and channel amendment).
docs/TODO.mdrestructured into three sections (real TODOs / under observation / rejected).docs/devlog.mdnow consolidated per release batch rather than per commit.
Verification
- Gates:
npm testfully green (including the zero-LLM deterministic golden-corpus regression). - Real runs: each of the three main threads has real-run evidence (
tf-mv3op3i2-0ok7nb/tf-mv3rdt0y-qmlxl3/tf-mv3upkft-2oggfu). - ⏳ Truncation rescue has not yet triggered on a real run (its unit test uses the real 5937-char truncated sample, plus deployment-artifact verification). Stated as-is; not claimed as verified.