Files
cdsl-cad/docs/autonomous-cad-reliability-and-token-target.md
2026-09-01 14:10:23 +08:00

564 lines
70 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 自主 CAD 生成协议:可靠性与 Token 效率目标
## 1. 目标与结论
本目标直接替换当前自主 CAD 协议,不保留旧任务兼容、迁移或恢复路径。目标是在不降低建模判断能力的前提下,消除当前“先生成大型 Markdown 建模计划,再按计划生成 CDSL”的硬门,并把每一轮 LLM 的输出缩小为可验证的单个建模动作。
必须达成:
- **LLM 决定下一步建模意图和操作。** 服务端不生成 CAD 步骤、不替 LLM 选 operation、不把需求编译成几何模板。
- **服务端只负责事实、约束和状态转换。** 它提供不可变需求、当前模型、拓扑、Runtime 合同、已接受动作及复核证据;校验 LLM 的选择,执行 CDSL,持久化真实结果。
- 不再要求新任务生成或复核 `modeling-plan.md`,不再出现计划版本、计划解析、计划动作 ID、计划 revision limit 或计划跳步门。
- 保留 `source-requirements.md``requirements.md``completion.md`、单 feature CDSL、候选构建、独立候选复核、检查点和最终独立复核。
- LLM 产生的每一项会改变状态、影响执行或作为验收依据的数据,必须通过固定 Pydantic schema 或 Runtime 动态 JSON Schema 校验。Markdown 和解释文本只由服务端从已验证数据渲染,绝不被解析为状态机输入。
- 可靠性的含义不是假定任何 LLM 永不产生错误格式,而是错误格式、过期引用和不符合 operation 合同的输出在**任何副作用之前**被确定性拒绝;它们不能创建候选、污染状态、消耗构建预算或触发无限重试。
- 文档和动作的格式问题必须是**无副作用的可诊断拒绝**;内部服务错误必须一次失败并保留检查点,不能被伪装成 LLM/CDSL 错误后循环重试。
- **v3 必须完成架构解耦。** “LLM 决策、Runtime contract、任务状态机、候选构建、持久化、渲染/复核”必须是职责明确、依赖方向受控的独立模块;不能继续集中在一个巨型 runner/service 中,或通过模块全局对象互相访问。
- 使用真实 API usage(可用时)和服务端上下文字节数度量 token 消耗,验收时以基线任务集比较,不以主观感觉判断。
这不是“取消计划后让服务端推断下一步”。计划能力仍存在,但由 LLM 在每个检查点结合当前事实重新判断;服务端保存的是实际发生过的动作账本,而不是预先要求 LLM 写完整未来路径。
## 2. 当前基线与已确认问题
当前路径由 `backend/app/services/autonomous_cdsl_generation.py` 实现:
1. 服务端创建不可变 `source-requirements.md`
2. 作者 LLM 写入并立即冻结 `requirements.md`
3. 作者 LLM 写入并立即冻结 `completion.md`
4. 作者 LLM 必须写大型 `modeling-plan.md`,独立模型审查它,失败后重写版本。
5. 作者 LLM 按计划动作读 Runtime contract,提交一条 CDSL feature。
6. 服务端构建候选,独立模型审查,接受后提交 checkpoint。
7. 完成清单覆盖后执行最终重建和视觉复核。
`cad_30933fe2fc6b` 已在 `rev_003` 生成正确的法兰:圆盘、中心贯穿孔、四个均布孔均已构建并接受。该任务随后失败的根因包括:
- `_final_review` 使用了未赋值的 `global_violations`,导致每次 `complete_task` 都触发 `NameError`。这是确定性的后端缺陷,不是 CDSL 或 LLM 错误。
- 调度器把上述内部异常归类为 authoring/fragment 错误,并允许重复 `complete_task`;因此无检查点进展的重试最终命中 `NO_PROGRESS_LIMIT`
- 建模计划审查要求精确 operation、selector、盲孔深度和 action 粒度,但计划又允许自然语言。这种“自然语言写入,严格执行含义”的双重合同使法兰计划在 `hole_blind | hole_wizard`、多孔单 action 和 through-equivalent 深度等问题上反复返工。
- `CDSL_MODELING_PLAN_MAX_REVISIONS=2` 的检查在计划已写入及审查后执行,并且后续循环仍可能继续,形成“已到上限却继续调用”的矛盾控制流。
已直接修复第一项:最终重建得到 `health` 后,现在会先调用 `_global_geometry_violations(...)`,再使用该变量。这一改动必须保留,并以最终复核回归测试覆盖。
### 2.1 真实 LLM 连通性测试
2026-08-31 在隔离临时任务根目录中,直接使用当前后端的 `AgentService._complete_once` 和完整 runner 调用配置的真实作者模型,依次发送了三个请求:矩形底板、简单法兰、带肋和四个安装孔的底板。第一个请求尚未产生工具调用或 CAD 工件时,OpenAI 作者请求已连续三次连接失败;runner 随后切换到 DeepSeek,同样连续三次失败。
测试发现 `_is_author_transport_error` 分支在所有作者 provider 失败后仍以约 4.5 秒间隔无限重试,使任务永久处于 `running`。测试已手动终止,以避免无意义 API/CPU 消耗;没有生成模型,因此不能把这次测试伪称为模型生成质量结果。该证据证明当前 transport 恢复策略存在流程缺陷,必须在 P0 修复:记录有限的 provider/总调用预算和指数退避,超限后将任务转为 `WAITING_RETRY`,保留 checkpoint 和调用诊断;只能由显式恢复操作或受控调度重新启动,而不能在同一个 run 中无限循环。
## 3. 不采用的方案
以下方案不满足本目标:
- **不保留现有 Markdown 计划,只改提示词。** 它仍把未来的操作、selector 和精确 Runtime 语义要求压到一次大输出中,根因未消失。
- **改成 LLM 一次输出大型 JSON/DAG 执行计划。** JSON 更容易解析,但不能消除大输出遗漏、过期 selector、前后依赖和重试 token 消耗;问题从 Markdown 转移到 JSON。
- **服务端依据未覆盖需求决定下一步。** 这会把建模策略藏在程序规则中,违反“LLM 决定下一步”的边界,也会让复杂零件的 CAD 判断不可审计。
- **取消独立候选/最终复核。** 能减少 token,但会显著降低最终几何可信度;优化应先删除重复的计划复核与冗余上下文,而不是删除实际结果复核。
- **用盲孔深度大于厚度作为所有通孔的唯一证明。** 这只是候选输入条件;最终仍须从拓扑/几何证明孔连接了预期两侧面、孔数和直径满足要求。
## 4. 新协议中的工件、结构化输出与验证
### 4.1 统一的结构化输出边界
不得让 LangChain、任何 provider 或 Pydantic 自身成为可信边界。它们只负责请求和解析;服务端必须对原始 tool arguments 再做一次 canonical validation,验证通过后才允许写库、构建候选或改变 revision。
```text
LLM provider
-> LangChain structured-output adapter
-> 原始 tool arguments / JSON
-> Pydantic 或 JSON Schema canonical validator
-> 当前 task、revision、权限和幂等校验
-> Runtime / CDSL / 几何验证
-> SQLite 事务提交
```
固定业务对象使用 Pydantic v2 模型生成 JSON Schema;例如需求草稿、审查 verdict、动作提案、修复决定都必须是 `extra="forbid"` 的模型。不同 operation 的 CDSL fragment 由 Runtime contract 生成动态 JSON Schema,不能伪装成一个“所有参数都可选”的静态 Pydantic 模型。需求草稿的外层是固定 Pydantic schema,但每个 `acceptance_claim.expected` 是 verifier registry 在当前任务启动时生成的 closed `oneOf`;这同样是动态 schema,不能用 `dict[str, Any]` 放过未知 claim 数据。
LangChain 仅封装在 `cad_agent/adapters/structured_llm.py` 或等价 adapter 内:
- 固定对象使用 `with_structured_output(PydanticModel)`
- 动态 operation contract 使用 `bind_tools()` 或 provider 的等价 tool schema 接口,传入服务端生成的 JSON Schema。
- 无论 provider 宣称支持 strict JSON、function calling 或 JSON mode,服务端都使用相同的 Pydantic/`jsonschema` validator 二次验证。
- 禁止使用 LangChain Agent、Memory、文本 JSON 提取、自动无限 re-ask 或自动 tool 执行。CAD runner 仍是唯一状态机。
- 不具备成功通过 provider conformance test 的 structured-output / tool-call 能力的模型,不可作为生产作者或审查模型。不能为了“支持任意模型”退回纯文本解析。
每次 LLM tool call 都经过同一条严格管线:限制一个允许的 tool name 和一个 call、限制原始 arguments 的字节数/JSON 深度、解析 JSON、schema canonical validation、当前状态与版本绑定、跨字段/几何 preflight,最后才进入事务或候选构建。provider 的 parser、LangChain 的 parser 和 Pydantic 的第一次反序列化都不是最终结论。服务端保留经脱敏的原始 arguments 与字段级错误用于诊断,但不会以“尽量修复”方式补全、重命名或猜测 LLM 字段。
工具的 `schema_name``schema_version`、当前 `working_head``contract_hash` 和 selector snapshot 由服务端 route/state 绑定,而不是信任 LLM 声称的版本。固定对象可以在工具 schema 中携带这些字段并做 canonical equality 校验;空参数命令(例如完成请求)则只以服务端暴露它的状态作为版本绑定。任何 schema 或 contract 变更都会使旧 pending action 失效,必须重新读取当前事实和合同。
### 4.2 需求和完成工件
`source-requirements.md` 是服务端保存的用户原文,不要求格式。服务端把它按原始段落或附件块生成稳定 `source_id`,只作为可引用证据,不尝试用规则理解自然语言。
LLM 不直接写 `requirements.md``completion.md`。它提交受严格 schema 约束的、分批且有上限的 `RequirementsDraftBatch`;服务端校验并保存 JSON,再渲染人类可读 Markdown。草稿阶段还必须使用结构化 `RequirementsPatchBatch` 修订 reviewer 指出的条目,并以零参数 `finalize_requirements_draft()` 明确请求进入独立复核。服务端在 source coverage 不完整时拒绝该最后一步,不自行猜测“需求已经写完”:
```text
source-requirements.md # 服务端创建,不可变
documents/source-index.json # 服务端生成:source_id -> 原始文本
documents/requirements-draft-v1.json # 仅已验证 RequirementsDraftBatch 合并结果
documents/requirements-review-v1.json # 严格结构化的独立审查结果
requirements-contract.json # 冻结的机器可验证需求与验收合同
requirements.md # 服务端从 contract 渲染,不作为程序输入
completion.md # 服务端从 contract 渲染,不作为程序输入
requirements-index.json # 服务端生成的 req/claim 索引
```
每次 `submit_requirements_draft_batch` 最多提交 8 条 requirement,避免大型一次性文档输出。外层固定 schema 至少包含:
```json
{
"items": [
{
"source_ids": ["src_001"],
"statement": "法兰为外径 120 mm、厚度 12 mm 的单一连通实体",
"assumptions": ["未指定标准时采用普通平面法兰"],
"acceptance_claims": [
{
"claim_kind": "solid_count_equals",
"expected": {"value": 1}
},
{
"claim_kind": "bbox_dimension_mm",
"expected": {"axis": "z", "value": 12, "tolerance_mm": 0.01}
}
]
}
]
}
```
`source_ids` 必须来自服务端 enum`claim_kind` 必须来自已注册 verifier enum;每一种 `claim_kind``expected` 都按该 verifier 专属 JSON Schema 校验。服务端分配不可变的 draft item ID、`req_###``claim_###`,不会接受 LLM 自定义 ID。
`RequirementsPatchBatch` 的每一项只能是 `replace``remove`,并且 `target_draft_id` 必须是当前 draft revision 的 enum。`replace` 必须携带完整、重新验证过的 requirement 对象,不能提交局部自然语言 patch;`remove` 必须给出长度受限的原因。这样 reviewer 修改的是可审计的单项,而不是要求模型重写整份文档。删除后若使 source 无覆盖,`finalize_requirements_draft()` 必须被拒绝。
冻结前,独立 reviewer 必须返回 `RequirementsReview`。它对**每一个** `source_id` 给出恰好一行 coverage(该行可引用一个或多个 requirement ID),并对每一个 draft item 给出 `pass``revise``waiting_for_user``pass` 只有在全部 source 已被映射、全部 claim 的 verifier 可用且不存在冲突时有效。一个 source 可以支撑多条 requirement;因此不要求 source 只被一条 requirement 引用,只要求 reviewer coverage 行唯一且完整。`waiting_for_user` 必须具有 machine-readable reason code 和受限的提问文本,不能用模糊 prose 隐藏关键尺寸或基准缺失。
`requirements.md``completion.md` 可以是自然、自由的 Markdown,因为它们是 JSON contract 的只读渲染。例如:
```markdown
- [ ] 单一连通实体,外径 120 mm、厚度 12 mm
- [ ] 同轴直径 40 mm 的中心贯穿孔
- [ ] 节圆直径 90 mm 上四个直径 10 mm 的均布贯穿螺栓孔
```
程序永远不从上述 Markdown 重新提取 ID、验收项、步骤或状态。任何可测几何需求若没有注册 verifier,必须在需求阶段报 `VERIFIER_UNAVAILABLE`,不得偷偷降级为“让视觉模型看一看”。确实只能依赖外观判断的要求可显式声明为 `visual` claim,但其风险必须在任务界面标记。
需求草稿、修订和 review 的 canonical schema 还必须有以下共同约束:所有数组有上下限,所有可见文本有长度上限,所有枚举/ID 来自当前服务端快照,嵌套对象 `additionalProperties=false`;禁止任意 JSON object、任意键值 metadata 和未注册 claim。若需求是文件命名、材料、单位或展示约束,也必须绑定相应的确定性 verifier;没有 verifier 就不能被冻结为可发布合同。
### 4.3 LLM 的单动作意图
LLM 不再写模型级执行计划。没有待处理动作时,作者只可调用 `propose_next_action`。该 tool 的 JSON Schema 由服务端传给模型并在服务端再次校验;不得接受 Markdown、自由 JSON 字符串或未知字段。
```json
{
"working_head": "head_5f2e...",
"intent": "在当前法兰顶面加工四个均布螺栓孔",
"requirement_ids": ["req_003"],
"atomic_id": "hole_blind",
"expected_change": "新增四个直径 10 mm、在节圆直径 90 mm 上等角分布并贯穿 12 mm 本体的孔"
}
```
约束:
- `intent``expected_change` 为短文本(建议分别最多 360 字符),只说明当前动作,不复述全任务。
- `requirement_ids` 必须来自 `requirements-index.json` 的 enum,最多引用五项。
- `atomic_id` 必须来自当前 Runtime `SUPPORTED_ATOMIC_IDS` enum。
- `working_head` 必须与服务端发出的 opaque current-head token 完全相等;Pydantic 检查其形状,canonical state validator 检查其相等性。
- 提案不包含 selector、草图、参数、深度、工作平面或 CDSL;这些属于后续读取精确 contract 后的 canonical fragment。
- 提案必须绑定当前 `working_head`。检查点变化后旧提案不可提交,需由 LLM 基于新事实重新提出。
因此格式错误无法“完全不发生”,但影响面被限制为一个极小、严格 schema 的无副作用调用:服务端返回字段级错误并保留模型/检查点,不会再生成计划版本、消耗候选构建次数或污染账本。
### 4.4 服务端动作账本
账本不是 LLM 输出,也不是执行计划。服务端在动作提案、拒绝、候选构建、复核和 checkpoint 后,以 append-only JSON Lines 写入 `actions/action-ledger.jsonl`。每一行是一个状态事件,便于审计、恢复和增量读取:
```json
{"schema_version":"cad.action-ledger.v1","sequence":7,"event":"proposed","action_id":"act_003","working_head":"main:rev_002","intent":"在当前法兰顶面加工四个均布螺栓孔","requirement_ids":["req_003"],"proposed_atomic_id":"hole_blind","expected_change":"新增四个直径10 mm贯穿孔","at":"2026-08-31T...Z"}
{"schema_version":"cad.action-ledger.v1","sequence":8,"event":"accepted","action_id":"act_003","working_head_before":"main:rev_002","revision_id":"rev_003","actual_atomic_id":"hole_blind","fragment_sha256":"...","selector_snapshot_id":"...","candidate_id":"candidate_...","review_path":"revisions/rev_003/reviews/candidate-review/candidate-review.json","coverage":[{"requirement_id":"req_003","status":"complete"}],"at":"2026-08-31T...Z"}
```
运行中的 pending action 是事务状态,不从 JSONL 反推。它只保存 `action_id``working_head`、提案内容、contract hash 和幂等 key。给作者的上下文只包含 pending action 与压缩后的最近动作摘要,完整账本仅用于审计/UI 查询,避免随模型复杂度线性膨胀 prompt。
### 4.5 CDSL 与完成调用
提交 CDSL 的动态 tool schema 不存在“统一的 feature JSON 模板”。它只暴露当前 pending action 已选择的一个 operation 的 author-owned 字段;下面只是一个形状示意,实际是否有 `sketch`、是否有 `params`、是否有 selector/reference token 由 operation contract 决定:
```json
{"fragment": {"sketch": {"...": "仅 contract 要求时存在"}, "feature": {"atomic_id": "与 pending action 相同", "params": {"...": "contract 精确字段"}}}}
```
移除 `batch_goal``plan_step_id``plan_action_id`。候选复核的目标、需求映射和 operation 均从 pending action 与真实 fragment 取得,不能由 LLM 在提交时再次声称。
动态 schema 必须由当前 Runtime 的**完整、版本化** `feature_atomic_contract` 唯一生成,并与 `contract_hash``working_head`、engine/profile schema revision 和 selector snapshot ID 绑定。当前 `feature_atomic_contract` 仅列出 required/optional 参数,而 `cdsl_authoring_schema.py` 仍按 operation 名称硬编码很多 JSON 类型、hole 特例和 pattern 注入;这会产生 contract drift,不能作为 v3 的终态。P2 必须把这些信息收拢到 Runtime contract registry,删除 authoring schema 中按 operation 前缀补规则的兜底分支。
每个 operation contract 至少声明以下数据,且 contract 自身先经 JSON Schema / registry integrity validator 验证:
```json
{
"atomic_id": "hole_blind",
"contract_version": "3.0",
"fragment_shape": {
"sketch": "forbidden",
"params": "required_object",
"selector_tokens": "required"
},
"author_params_schema": {"type": "object", "additionalProperties": false},
"selector_policy": {
"slot": "params.host_face",
"token_kind": "face",
"min_items": 1,
"max_items": 1,
"snapshot_bound": true
},
"server_injected_paths": ["params.host_face"],
"reference_policy": {"mode": "none"},
"semantic_preflight": ["host_face_exists", "hole_positions_on_host_plane"],
"candidate_verifiers": ["cylindrical_bore", "through_cylindrical_bore"]
}
```
其中 `author_params_schema` 是 closed JSON Schema,必须递归关闭其嵌套对象。禁止用 `{}``type: object` 未限制 properties、任意 `dict` 或“其它 operation 以后再解释”的 fallback 暴露给作者。`hole_wizard``hole_type``thread``countersink``counterbore` 等嵌套对象必须各有枚举/closed 子 schema;当前的开放对象定义不满足此要求,必须在该 operation 可暴露前补齐。
动态 schema 必须精确表达以下 operation 差异,而不能靠 prompt 约定:
- `fragment_shape.sketch=required``sketch.workplane``sketch.profile` 必填;`forbidden``sketch` 出现即拒绝。profile 类型和每层字段同样由 closed schema 限制。
- `fragment_shape.params=required_object``params` 必须存在并匹配该 operation 的专属 schema;若 operation 没有 author-owned 参数,contract 明确指定 `params` 是必填的空 object 还是 forbidden,不能假设所有 feature 均需或均不需参数。
- `selector_policy` 只能为 `forbidden``required` 或明确的 `optional`。required selector 的 token schema 是当前 snapshot 中匹配 kind 的 opaque token **enum**,并有精确数量上限;没有有效 snapshot 时根本不暴露 fragment tool。`host_face`、mirror plane 等 server-owned selector 只由 resolver 注入,LLM 提供原始 selector object 或注入字段即拒绝。
- `reference_policy` 处理 feature-source、reference plane/axis 等关系。禁止当前实现中“默认把最后一个 committed feature 当 pattern source”的通用猜测;若关系不是 contract 可唯一推导,schema 必须要求来自当前 feature-reference snapshot 的 opaque token,并由服务端解析为 Runtime ID。
- 每个 operation 只允许自身的 required/optional params`additionalProperties=false`;例如 `extrude_cut_blind.distance_mm` 不能替换为 hole 的 `depth_mm`hole 的 `positions` 也不能出现在 extrude。所有数字必须是有限值,并满足 Runtime 安全范围、单位和 operation 专属的跨字段限制。
- `atomic_id` 必须同时等于 pending action、active contract 和动态 schema 的 `const`;三者任一不一致均在构建前拒绝。
- 新增 Runtime operation 时,必须同时新增完整 operation contract、contract integrity fixture、动态 schema fixture、canonical validator 测试、semantic-preflight 测试、引擎执行测试和对应 verifier;缺任一项不得进入作者可选 `atomic_id` enum。
动态 schema 校验成功后仍必须依次通过:当前 revision/head 校验、contract hash 与 registry revision 校验、selector/reference snapshot 校验、operation semantic preflight、静态 CDSL schema、完整 materialized CDSL validation 和隔离 CDSL-only rebuild。前六项均不产生候选目录;只有通过后才消耗候选构建预算。schema 不能表达的关系必须由 preflight/geometry validator 检查,例如工作平面正交且法向非零、profile 不自交、hole position 位于宿主面、revolve axis 位于草图平面,以及为了满足“贯穿” claim 的 `hole_blind``extrude_cut_blind` 的切削方向、有效行程和出口面连通性。
`complete_task` 改为无参数 tool。删除 `self_review`,因为作者的自我声明不能作为完成证据。服务端仅在当前 revision 的独立 coverage 全部完成且没有 pending/rejected repair 时暴露该 tool。
### 4.6 每类 LLM 输出的可信边界
| LLM 输出 | 输出方式 | 必须由程序验证 | 不由它控制的内容 |
| --- | --- | --- | --- |
| 需求草稿/修订/提交复核 | `RequirementsDraftBatch``RequirementsPatchBatch``finalize_requirements_draft()` | 字段、source/draft-ID enum、批量上限、claim kind 的动态 `oneOf`、重复项、累计 source coverage | Markdown 文档、req/claim ID、draft/review 状态、冻结状态 |
| 需求独立审查 | `RequirementsReview` Pydantic schema | 每个 source_id 的唯一 coverage 行、每个 draft item verdict、引用的 req/claim 存在、`WAITING_FOR_USER` reason code | 是否冻结由服务端 coverage gate 决定 |
| 下一动作 | `NextAction` Pydantic schema | requirement ID enum、Runtime operation enum、working head、无 pending action、幂等键 | action_id、pending 状态、实际 CDSL ID |
| 观察/测量/contract 请求 | 固定 Pydantic tool schema,动态 enum 绑定当前 head/snapshot | 参数范围、当前 revision、selector kind/limit、operation enum;每回合只接受允许的一个 tool call | 观察结果、contract、selector/reference token 均由服务端生成 |
| CDSL feature | 当前 operation 的动态 JSON Schema | contract hash、`const atomic_id`、fragment shape、递归 closed params、selector/reference enum、静态 CDSL、语义 preflight、引擎 preflight | feature/sketch ID、dependency、host face、selector/reference 解析 |
| 诊断、回滚与完成请求 | `GeometryConclusion``RollbackCheckpoint``complete_task()` | decision enum、当前 evidence ref enum、rollback token、head、文本/数组上限;完成 gate 由服务端先验证 | 几何诊断证据、回滚可达性、发布判断 |
| 候选审查 | `CandidateReview` Pydantic schema | candidate/revision enum、claim coverage 的精确集合、verdict enum、证据上限;确定性 verifier 必须先通过 | checkpoint 提交、coverage 更新 |
| 最终审查 | `FinalReview` Pydantic schema | current revision、所有 final claim 的精确集合、verdict enum、证据上限;所有 deterministic claim 必须通过 | 发布、published revision |
| 可见解释/意图文字 | 普通文本字段,长度限制 | 仅编码、安全和长度检查 | 不参与任何状态转移或 CAD 参数计算 |
“结构化输出通过”只证明对象格式和引用有效,不证明 CAD 语义必然正确。语义正确性必须由 source coverage、requirement acceptance contract、Runtime、几何 verifier 和独立 review 共同证明;其中 deterministic verifier 失败时,任何 LLM 的 accept verdict 都不能覆盖失败。
### 4.7 Canonical schema 目录与二次校验
以下目录是 v3 必须实现的**唯一** LLM 输入合同。每个固定模型均使用 Pydantic v2 的 strict model`extra="forbid"`、显式长度/数量限制),由服务端导出 JSON Schema;动态 enum 和 dynamic `oneOf` 在每次 tool 暴露时由服务端收窄。任何新的 state-changing LLM tool 必须先加入本表、fixture、conformance test 和错误映射,不能临时添加自由 object 参数。
| Tool / 输出模型 | 必填结构化字段 | schema 类型 | 格式后仍必须程序校验 |
| --- | --- | --- | --- |
| `submit_requirements_draft_batch` / `RequirementsDraftBatch` | `items[1..8]`;每项有 `source_ids``statement``assumptions``acceptance_claims` | Pydantic outer + verifier registry 的 closed claim `oneOf` | source enum、去重、claim 语义/单位、可用 verifier、draft transaction |
| `patch_requirements_draft` / `RequirementsPatchBatch` | `patches[1..8]``target_draft_id``op=replace|remove`replace 携带完整 item | Pydantic + current draft-ID enum | 目标存在且属于当前 draft revision、替换后的 coverage/去重 |
| `finalize_requirements_draft` | 空 object | fixed empty schema | 至少一个 draft item、无缺 source、无不可用 claim 后才可进入 review |
| `review_requirements` / `RequirementsReview` | `verdict`、每个 source 的唯一 coverage row、每个 draft item verdict、`issues[]` | Pydantic + source/draft/claim ID enum | coverage 精确集合、issue code、approve gate;服务端而非 reviewer 冻结 contract |
| `propose_next_action` / `NextAction` | `working_head``intent``requirement_ids``atomic_id``expected_change` | Pydantic + Runtime operation/requirement ID enum | head equality、无 pending action、operation available、idempotency |
| 事实读取工具 | 例如 `inspect_topology(kind, limit)``get_cdsl_operation_contract(atomic_id)``render_section(origin_mm, normal)` | Pydantic,动态 operation/head/snapshot enum | 参数范围、访问当前 revision、预算/缓存;结果只能由服务端生成 |
| `submit_cdsl_fragment` | 只有当前 operation contract 定义的 fragment | Runtime-generated Draft 2020-12 JSON Schema | contract/schema/snapshot hash、引用解析、cross-field semantic preflight、materialized CDSL schema、engine preflight |
| `record_geometry_conclusion` / `GeometryConclusion` | `working_head``evidence_refs``root_cause``decision`、受限 `corrective_intent` | Pydantic + current evidence enum | evidence 属于同一 head、decision 可达;`corrective_intent` 不直接成为 CDSL |
| `rollback_checkpoint` / `RollbackCheckpoint` | `working_head``checkpoint_token`、受限 reason | Pydantic + active lineage enum | token 是祖先、没有 candidate/transaction 冲突、原子 branch transition |
| `review_candidate` / `CandidateReview` | `candidate_id``revision/head``verdict`、精确 claim coverage、受限 evidence/issues | Pydantic + candidate/claim enum | candidate identity、确定性 claim gate、reviewer 不能覆盖 deterministic result |
| `complete_task` | 空 object | fixed empty schema | 没有 pending action/repair,所有 deterministic claim pass;为 final review 创建幂等工作项 |
| `review_final` / `FinalReview` | `revision/head``verdict`、精确 final claim coverage、受限 evidence/issues | Pydantic + final claim enum | final rebuild identity、全局 invariant、deterministic/visual gate、一次发布事务 |
`GeometryConclusion.decision` 只能是 `return_to_action_selection``rollback``waiting_for_user`;它不包含 feature ID、参数、selector 或下一段 CDSL。选择修复仍由下一次 `NextAction` 明确作出,避免诊断对象暗中变成第二套执行计划。`CandidateReview``FinalReview` 允许模型提出 reject/repair;对确定性 claim,服务端只把 reviewer 的 accept 当作额外条件,而不是证明。
## 5. 完整执行流程及 LLM 边界
| 阶段 | 输入/产物 | LLM 生成内容 | 服务端职责 | 失败后的唯一去向 |
| --- | --- | --- | --- | --- |
| 0. 创建 | 用户请求 | 无 | 创建 `source-requirements.md`、任务与 run | 请求错误,拒绝创建 |
| 1. 需求草稿 | source index + 用户上下文 | `submit_requirements_draft_batch(RequirementsDraftBatch)`,每次最多 8 项;按需 `patch_requirements_draft(RequirementsPatchBatch)`,最后 `finalize_requirements_draft()` | outer Pydantic、source/draft-ID enum、verifier dynamic schema、去重和批量事务;只保存 JSON | `AUTHOR_FORMAT_INVALID``REQUIREMENTS_COVERAGE_INCOMPLETE`,不写 Markdown、不进入建模 |
| 2. 需求独立复核 | source index + draft contract | `review_requirements(RequirementsReview)` | coverage 行、假设/冲突/验收可行性;通过后冻结 JSON 并渲染 `requirements.md` / `completion.md` | `revise` 回到阶段 1;歧义为 `WAITING_FOR_USER`;缺 verifier 为 `VERIFIER_UNAVAILABLE` |
| 3. 选择下一动作 | frozen contract、claim coverage、当前模型摘要、账本摘要、Runtime operation enum | `propose_next_action(NextAction)` | Pydantic、ID enum、head、operation、幂等和 pending-action 校验 | 无副作用 `AUTHOR_DECISION_REJECTED` 或 Runtime 前置条件错误 |
| 4. 收集事实 | 当前 checkpoint | LLM 自主调用结构化 inspect/measure/render/topology/contract tools | 返回真实、版本绑定数据;为动态 fragment 生成 selector/reference enum、限额和缓存 | snapshot 过期或 selector/reference 不匹配,保留 checkpoint,重新观察 |
| 5. 生成 CDSL | pending action + 精确 operation contract + 相关 snapshot | `submit_cdsl_fragment(DynamicOperationSchema)` | contract/head/snapshot-bound dynamic JSON Schema、静态 CDSL、语义/引擎零副作用 preflight | `CDSL_SCHEMA_INVALID``RUNTIME_PRECONDITION_FAILED`,只允许修正当前动作;不消耗候选尝试 |
| 6. 构建候选 | materialized CDSL | 无 | 隔离 rebuild、健康检查、拓扑、deterministic claim verifier、渲染 | `CANDIDATE_BUILD_FAILED``CLAIM_VERIFICATION_FAILED`,保留基线并进入诊断/修复或回滚 |
| 7. 独立候选复核 | 渲染、真实 CDSL、拓扑、pending action、只读 claim 结果 | `review_candidate(CandidateReview)` | 验证结构化 verdict/claim coveragedeterministic claim 失败时强制 reject | reject 形成明确 repair cardreview 服务故障为 typed service failure,不让作者重做几何 |
| 8. 写账本/检查点 | accepted candidate | 无 | 原子提交 revision,追加 accepted ledger,更新 claim coverage,清除 pending action | 存储失败必须原子回滚,不出现半提交 |
| 9. 下一轮 | 新 checkpoint | 回到阶段 3,由 LLM 决定下一动作 | 仅提供最新事实 | 同上 |
| 10. 最终完成 | 当前 revision、claim coverage、最终渲染 | `complete_task()`,无参数;`review_final(FinalReview)` 由独立 reviewer 输出 | CDSL-only rebuild、全部 deterministic claim、全局几何不变量、结构化最终独立复核、发布 | repair 回阶段 3;内部故障一次标为 `FAILED_INTERNAL` |
阶段 3 的“下一步”必须由 LLM 做决定。服务端不可根据未覆盖的 `req_003` 自动构造“加工螺栓孔”;它只能在 LLM 提出 `hole_blind` 后检查该选择是否是当前 Runtime 支持的原子操作、是否与 checkpoint/contract 相容,以及是否可安全进入下一阶段。
## 6. 可靠性规则
### 6.1 明确错误分类
定义可序列化的错误码和类别,禁止将 Python 异常文本当作 authoring error
- `AUTHOR_FORMAT_INVALID`tool 参数或 canonical CDSL schema 无效;无 CAD 副作用,可限次数修正。
- `AUTHOR_DECISION_REJECTED`:动作与当前 pending/head/contract 不一致;无 CAD 副作用,要求重新选择或修订。
- `STALE_WORKING_HEAD`command 的 head、state version、contract 或 selector/reference snapshot 已过期;无 CAD 副作用,返回最新事实,禁止自动合并或覆盖新的 checkpoint。
- `FAILED_AUTHOR_FORMAT`:同一 schema 的字段级修正次数达到上限,或 provider 持续不能交付该 schema;终止本 run 并保留 checkpoint,不能改记为 `NO_PROGRESS_LIMIT` 或降级到自由文本。
- `RUNTIME_PRECONDITION_FAILED`selector 不存在/歧义、body/host 缺失、操作不支持;保留 checkpoint,要求新的观察或动作决策。
- `RUNTIME_CONTRACT_INVALID`operation registry 缺少 closed field schema、注入/selector/reference policy、semantic preflight 或与 engine schema 不一致;这是部署/代码缺陷,feature 不得暴露给作者,也不能归因于 LLM。
- `CANDIDATE_BUILD_FAILED`:BRep/STEP 构建失败;消耗候选预算,进入诊断、修复或回滚。
- `CANDIDATE_REVIEW_REJECTED`:几何已构建但不符合动作或需求;保留证据,LLM 决定修复/回滚。
- `VERIFIER_UNAVAILABLE`:冻结的 requirement claim 没有已注册且可运行的 verifier;不得创建 task contract 或发布。
- `CLAIM_VERIFICATION_FAILED`:候选/最终 deterministic verifier 得到 failLLM reviewer 不能覆盖该结果。
- `MODEL_STRUCTURED_OUTPUT_UNSUPPORTED`provider/model 未通过当前 schema 的 conformance suite;任务开始前拒绝,不进入 author loop。
- `AUTHOR_TRANSPORT_UNAVAILABLE``REVIEW_SERVICE_UNAVAILABLE``RENDER_SERVICE_UNAVAILABLE``STORAGE_FAILURE`:基础设施失败;不归入 no-progress、不允许 author 重复 CDSL。使用相同幂等键和有限指数退避重试服务操作,超限后进入 `WAITING_RETRY`,由显式恢复操作或受控调度重新开始。
- `FAILED_INTERNAL`:未预期异常(例如 `NameError`);记录 traceback/版本/调用幂等键,立即终止该 run,保留最后 checkpoint。
- `WAITING_FOR_USER`:源需求冲突、关键尺寸/基准不可合理假设、或多轮文档复核无法消除的语义歧义;不是 `failed`
`NO_PROGRESS_LIMIT` 只统计作者在允许的观察/决策阶段反复作出没有状态推进的合法但无效选择;同一无副作用格式错误超过上限应归为 `FAILED_AUTHOR_FORMAT`。它绝不能统计 `FAILED_INTERNAL``RUNTIME_CONTRACT_INVALID`、verifier/review/render/network/storage 故障,也不能把重复 `complete_task` 视为可继续作者修正的机会。`WAITING_RETRY` 只用于可恢复的基础设施失败,`WAITING_FOR_USER` 只用于用户决定缺失,二者都不能掩盖 author format failure。
### 6.2 幂等与事务
- 每个状态改变 tool call 有 `invocation_id`;每个候选/最终复核有基于 `task_id + working_head + action_id + fragment_hash` 的幂等键。
- 同一 `complete_task` 对同一 revision 最多执行一次最终重建/复核;调用中断后恢复相同结果或明确失败,不能重新进入作者循环。
- candidate commit、task revision 更新、pending-action 清除和 ledger append 必须在同一事务内完成。
- 新协议的权威可变状态采用 SQLite(任务、run、pending action、ledger index、invocation、coverage),STEP/GLB/CDSL/Markdown/渲染仍保留在任务目录作为不可变工件。`WorkspaceStore` 重构为“数据库状态 + 文件工件”,不允许 JSON 与数据库双写且各自成为事实来源。
- `task.json` 可以作为 API/人工查看的派生快照,不能再是并发状态机的权威来源。
- 外部 build/render/review 不能与 SQLite 假装存在同一事务。候选工件先写入不可见的 staging 目录,并带有输入 head、fragment hash、engine version 和每个文件 sha256 的 manifest;只有所有 preflight/build/verifier 都成功,才原子 rename 到不可变 revision artifact 位置。随后 SQLite 条件事务写入 revision、coverage、ledger index 和已存在 artifact manifest 引用;API 只通过 SQLite 引用读取工件,因此在数据库提交前已发布的文件仍不可见。进程崩溃时恢复器验证 manifest/hash,清理未引用工件或复用已发布的同 hash 工件;不会让 active revision 指向尚未发布的文件。
- 状态事件写入 transactional outbox,与状态迁移同一 SQLite 事务提交;stream/UI 通知由 outbox dispatcher 幂等发布,不能由 command handler 直接 emit。这样断连、重放或前端失败不会回滚已确认的 CAD checkpoint,也不会导致重复 build。
### 6.3 几何验证
- selector 必须来自当前 topology snapshot;零个候选报 `selector_not_found`,并列候选报 `selector_ambiguous`,不可默认取第一个。
- 对“贯穿孔”建立 topology 断言:孔轴对应的圆柱面必须连通目标进/出平面;验证孔数、直径、位置/节圆和穿透方向。`depth_mm >= body_thickness` 只可作为 preflight 辅助证据。
- 对需要“等效贯穿”的 `hole_blind``extrude_cut_blind`preflight 必须从实际宿主面/工作平面、切削方向和目标实体计算最小出口距离;不足则拒绝为 `RUNTIME_PRECONDITION_FAILED`。候选与最终阶段仍以拓扑连通性为最终结论,不能以参数名称或深度文字代替。
- 多位置 `hole_blind` 在同一 host face、孔径和深度一致时必须允许为一个 action/一个 feature;不得被 review 层拆成四条虚假要求。
- 全局不变量(单实体、显式尺寸等)在候选和最终重建两处都执行,二者使用同一函数;最终复核不得引用未初始化的局部变量。
### 6.4 验收 verifier registry
`requirements-contract.json` 中的每一个 `acceptance_claim` 必须引用一个注册 verifier。每个 verifier 是服务端代码,不是 LLM prompt,至少定义:
```text
claim_kind
expected_json_schema
required_artifacts # CDSL / rebuild report / topology / render
evaluate(current_revision) -> pass | pending | fail | unavailable
evidence() -> 结构化测量和工件引用
```
首批必须覆盖当前项目已能可靠观测的内容:
| claim_kind | 程序化证据 |
| --- | --- |
| `solid_count_equals` | CDSL-only rebuild 的 `solid_count` |
| `bbox_dimension_mm` | rebuild bbox 指定轴和容差 |
| `cylindrical_bore` | topology 的圆柱面、直径、轴线和位置 |
| `through_cylindrical_bore` | bore verifier 加上入口/出口平面连通性 |
| `circular_hole_pattern` | 孔数、直径、节圆半径、角间距、宿主面与穿透状态 |
| `coaxial` / `coplanar` | topology 几何轴线、法向和容差 |
| `single_connected_body` | rebuild solid count 与连通性 |
| `visual` | 固定 render + 独立 reviewer;必须明确标为非确定性 |
每个 checkpoint 都计算所有 claims:尚未由前序几何满足的 claim 为 `pending`,已经被错误几何破坏的 claim 为 `fail`。候选不得因未来工作仍是 `pending` 而被拒绝;但如果动作引用的 requirement 已经被 `fail`、或任何全局 invariant 为 `fail`,候选必须拒绝。最终发布要求所有 deterministic claim 为 `pass`,所有 visual claim 获独立 reviewer `pass`。LLM reviewer 只能拒绝或为 visual claim 提供证据,永远不能把 deterministic `fail` 改成 `pass`
verifier registry 的注册也是可靠性边界:registry 启动时必须校验 `claim_kind` 唯一、`expected_json_schema` 为有效的 closed schema、required artifacts 可由当前 engine/rebuild 产生、`evaluate` 可序列化返回结构化 evidence。任何 verifier 在候选/最终运行时不可用都返回 `unavailable``VERIFIER_UNAVAILABLE`,不得把 claim 静默转成 visual。
### 6.5 Provider conformance 与模型切换
切换模型不得修改 CAD runner、Pydantic 模型、Runtime contract 或 verifier。新增 provider/model 时先运行真实 API conformance suite,成功后才写入 `model_capabilities`
- 固定 Pydantic schema:必填字段、enum、嵌套对象、数组上限、`additionalProperties=false`
- 强制指定 tool 与模型返回多个 tool call 时的行为。
- 每一个已注册 Runtime operation 的动态 fragment schema,至少验证 required params、forbidden params、`requires_sketch` 差异、selector token enum 和 `const atomic_id`
- usage、timeout、429、断连、空 choices、无 tool call 和无效 JSON 的统一错误映射。
- provider 的 strict schema、普通 tool calling、JSON mode 分别记录;只能选择实测通过的模式。
能力档案不通过时拒绝启动任务,返回 `MODEL_STRUCTURED_OUTPUT_UNSUPPORTED`。格式失败时允许有限次数的同 schema re-ask,错误信息只含 validator 的字段级结果;每次失败均不创建候选、不消耗 build 预算、不改变 revision。达到格式上限必须显式进入 `FAILED_AUTHOR_FORMAT`;只有 transport/限流等基础设施重试超限才进入 `WAITING_RETRY`。两者都绝不降级为自由文本执行。
### 6.6 架构、依赖与状态机边界
v3 采用 Ports and Adapters(六边形)架构、显式 command handler 和有限状态机。目的不是增加抽象层数量,而是让“LLM 选择下一动作”和“程序证明、执行、持久化该动作”在代码上无法相互越界。`autonomous_cdsl_generation.py` 当前同时承担 prompt、tool schema、状态迁移、CDSL materialization、文件读写、候选构建、review 和重试;v3 不得保留这种万能 service。
依赖方向只能由外向内:API/UI 与 adapter 可依赖 applicationapplication 可依赖 domain 与 portdomain 不得导入 FastAPI、LangChain、SQLite、文件路径、engine、renderer 或 settings。adapter 只能实现 port,不能直接改变 task state 或绕开 command handler。composition root 是唯一可以同时 import application、adapter 和 settings 的位置。
```text
API / worker / stream
-> application: command handlers + workflow coordinator
-> domain: immutable state, transitions, contracts, policies
<- ports: TaskRepository, ArtifactStore, ModelGateway, CadRuntime,
ReviewGateway, VerifierExecutor, EventPublisher, Clock
<- adapters: SQLite/files, LangChain/providers, CDSL engine,
renderer, reviewer, outbox dispatcher
```
模块职责固定如下:
| 层级 | 模块/对象 | 允许做什么 | 明确禁止 |
| --- | --- | --- | --- |
| domain | `TaskState``PendingAction``Revision``OperationContract`、claim/verifier policy、transition function | 不可变 value object、跨字段规则、合法状态迁移、typed error/result | I/O、网络、文件、SQL、prompt 拼接、选择下一 CAD action |
| application | `CommandHandler``WorkflowCoordinator``UnitOfWork` 使用方、context assembler | 接收已验证 command、读取 snapshot、调用 port、安排幂等 side effect、提交 transition/outbox | 直接解析原始 LLM JSON、直接访问 SQLite/路径、按 operation 名称写参数规则、从 requirement 推导下一动作 |
| ports | Python `Protocol`/interface | 声明 repository、artifact、LLM、runtime、review、event 等依赖的输入输出和 failure contract | 保存业务状态、提供默认实现、泄漏 provider/engine 私有对象 |
| adapters | `StructuredModelGateway`、SQLite repository、artifact store、CDSL runtime、renderer/reviewer、outbox dispatcher | 调用外部系统并翻译为 port 的 typed result/error | 决定 workflow transition、修改 domain object、吞掉/重新归类内部异常 |
| delivery | FastAPI、worker、stream、frontend mapper | 鉴权、请求/响应、启动 command、消费 outbox event | CAD 规则、状态迁移、直接读写 task 文件 |
固定采用以下模式和约束:
- **Command + Result。** 每个 state-changing tool 映射到一个 typed commandhandler 只返回 `Accepted``Rejected(typed_error)``Waiting``FailedInternal` 这类结果。预期业务失败不以 Python exception 驱动控制流;adapter 未预期 exception 在边界转为 `FAILED_INTERNAL` 并携带 correlation ID。
- **有限状态机。** 持久化状态至少为 `DRAFTING_REQUIREMENTS``REVIEWING_REQUIREMENTS``AWAITING_ACTION``ACTION_PENDING``CANDIDATE_BUILDING``CANDIDATE_REVIEW``FINAL_VALIDATION``WAITING_RETRY``WAITING_FOR_USER``COMPLETED``FAILED`。观察/测量是只读 command,不新增持久化 phasetool 可见性由 state、pending action 和 snapshot 派生,不能由 prompt 文本隐式决定。
- **Strategy + registry。** operation contract、semantic preflight 和 verifier 以已验证 registry entry 注册;不得以 `if atomic_id.startswith(...)` 在 runner 中散落规则。registry 选择由已验证 `atomic_id` 完成,不能演变为 service locator 或反射执行任意插件。
- **不可变快照与乐观并发。** command 带 `working_head`、schema/contract hash、必要的 selector/reference snapshotrepository 以 task state version/head 做 compare-and-swap。冲突返回 `STALE_WORKING_HEAD`,不会合并或覆盖较新的 checkpoint。
- **Unit of Work + transactional outbox。** SQLite 是唯一状态提交点;工件、LLM、engine、renderer 等非事务性副作用通过 invocation/candidate staging 和 outbox 与状态机衔接,不允许“先更新 task.json,再希望文件/stream 成功”。
- **依赖注入和 composition root。** handler 构造时显式传入 ports;测试替换为 in-memory/fake adapter。禁止 handler/validator 内部调用 `load_engine()`、读取全局 settings、创建 HTTP client 或直接 new `WorkspaceStore`
状态迁移必须集中在纯函数/transition table 中,并作为架构测试覆盖。一个 handler 的标准过程是:读取 immutable snapshot -> canonical/schema/state validation -> 注册或复用 invocation idempotency record -> 调用必要 port -> 以 expected state version 计算 domain transition -> 单一 Unit of Work 提交 state、ledger index、outbox。build/review 这类长时操作先持久化 `processing` invocation/candidate 状态,重启后从该记录恢复;同一 idempotency key 只能得到一个最终 result,不允许重新生成第二个候选。每一次 command、adapter call、candidate、review 和 outbox event 都记录同一 `task_id``run_id``invocation_id`、head/state version 的结构化 correlation fields;日志不得保存密钥、完整用户附件或未脱敏 prompt。
LLM 的回合管理也服从这个边界:`WorkflowCoordinator` 只根据当前 workflow state 请求 `ModelGateway` 输出允许的一个 structured command,然后交给对应 handler;它不分析 requirement 文本、不了解某个 hole 的字段,也不自行选择 operation。prompt/context assembly 是 application service,输入只能是 domain projection 和 port 返回的事实快照;operation schema 由 runtime contract adapter 提供。
为防止架构随时间退化,测试必须检查 import dependency rules、每个 port 的 adapter conformance、domain transition table、crash recovery/outbox 重放和并发 CAS 冲突。`autonomous_cdsl_generation.py` 只能在过渡期作为迁移入口;v3 发布前必须删除其中的业务实现,替换为薄 composition/compatibility-free bootstrap,不能只是把原函数移动到新文件。
### 6.7 真实 LLM 端到端评测与 Codex 执行门
provider conformance 只证明某个模型在小型、受控 schema 提示下能返回合法 tool arguments;它不能证明该模型在完整 requirements、动态 operation contract、真实 CAD 结果和多轮状态机中能稳定完成零件。因此 v3 必须提供可由 Codex 非交互执行的真实评测入口,并将其作为完成该目标与发布的硬门。实现本目标的 Codex 必须实际运行它、读取失败工件与诊断、修复可修复的实现缺陷后重新运行;不得只运行 mock/unit tests 后声称目标完成。
必须新增命令:
```text
cd backend
python -m app.cad_agent.evals.live --suite release --require-live
```
该命令默认从当前 `Settings` 取得已选择的 author provider/model 和独立 reviewer provider/model;允许以显式、非秘密的 provider/model ID 覆盖,便于逐个验证已配置模型。凭据只从现有配置来源读取,CLI 参数、输出、工件和日志绝不回显密钥。它必须经由生产 `StructuredModelGateway`、生产 `CadRuntime`、生产 `ReviewGateway`、v3 `WorkflowCoordinator`、SQLite repository 与 ArtifactStore adapter 运行,测试代码不得替换 LLM、CAD engine、reviewer、状态机或动态 schema validator 为 mock/fake。唯一允许的隔离是每次评测创建临时 v3 SQLite 数据库和独立 artifact root,绝不读取、修改或发布普通用户 task。
命令开始时先以实际 provider 请求执行选定模式的 conformance preflightauthor 与 reviewer 均需成功。配置缺失、凭据无效、网络不可达、provider 限流、模型未通过 structured-output capability 或引擎不可用时,命令写出结构化 `LIVE_EVAL_BLOCKED`/对应 typed error 并以非零退出。`--require-live` 禁止任何 skip、离线 fallback、mock fallback 或把 `WAITING_RETRY` 记为通过。只有用户显式选择不执行 live eval 的开发场景才允许 `--allow-skip`;该模式产生 `skipped`,永远不满足本目标的完成或发布验收。
评测分层以控制成本但保留真实覆盖:
- `smoke`:矩形底板和简单法兰各一次,用于 Codex 在完成高风险改动后快速验证真实 author/reviewer/engine 串联。
- `release`:矩形底板、法兰、带肋和安装孔的支架、含 face/edge selector 的修饰特征;每个场景至少连续运行三次,以独立 task/run 执行。任务需求、units、验收 claims、最大 author/reviewer turn 数、最长 wall time、总 token/调用预算和期望终态作为版本化 fixture 保存在仓库。
- 新增或修改 operation contract、selector/reference policy、verifier 或动态 schema 时,`release` 还必须包含该 operation 的最小真实生成场景;不能只补 unit fixture。
每个 live run 的成功只取决于当前 revision 的可验证结果,不取决于 LLM 是否恰好选择某个预期 feature sequence。它必须:完成到 `COMPLETED`、通过全部 deterministic claims 和必要 visual review、生成可读取的 immutable artifacts;无 `FAILED_INTERNAL``NO_PROGRESS_LIMIT`、未终止 `running`、重复 revision、重复 complete/build invocation 或未分类异常;所有 state-changing LLM 输出均有 raw-arguments hash、canonical validation、head/contract/snapshot binding 的审计记录;任何格式拒绝均在候选创建前发生。reference happy-path fixture 的 schema/decision rejection 计数必须为零;若出现,即使系统后来恢复,也视为 live quality failureCodex 必须报告字段级原因并调整 schema/context/contract 或模型 capability,而不能隐藏为普通重试。
每次运行写入 `live-evals/<run_id>/report.json` 和链接到隔离工件的 manifest。报告至少包含:git revision、protocol/contract/verifier 版本、author/reviewer provider+model ID、实际 structured-output mode、每场景和每重复的最终 lifecycle、typed failure、所有 invocation/candidate/revision IDs、每个 claim 结果、schema rejection/重试/rollback 计数、token usage/上下文字节/耗时、预算是否超限,以及脱敏后的 correlation ID。保存 JSON summary、ledger、CDSL、拓扑、rebuild/verifier evidence 和 reviewer verdict;禁止保存密钥、完整未脱敏 prompt、附件原文或 provider 响应中的敏感 metadata。
Codex 的最终交付必须在结果中逐项说明实际执行的 live command、author/reviewer model、通过/失败场景、可定位的 report/artifact 路径、token 用量与任何失败的根因。发生网络/凭据等外部阻塞时,Codex 必须明确报告 `LIVE_EVAL_BLOCKED`,而不是宣称真实模型质量已验证;这会阻止把本目标标记为完成。运行有成本,因此开发中先跑相关 `smoke`,但实现完成前必须运行一次无 skip 的完整 `release` suite。
## 7. Token 优化目标与实现规则
优化优先级是减少无效轮次,其次再压缩每轮上下文;不能通过删除必要的运行时合同或独立复核来换 token。
1. 删除新任务的大型 `modeling-plan.md`、它的 parser、一次或多次计划 review 和重写循环。
2. requirements contract 由最多 8 项的结构化 batch 构成;`requirements.md` / `completion.md` 由服务端渲染,作者不再生成或重写 Markdown。复核通过后,建模循环不再重复发送 `source-requirements.md`,只发送冻结 contract 的紧凑摘要、requirement/claim ID 和未完成状态。最终复核仍发送 source,以防冻结 contract 遗漏源需求。
3. 每轮作者上下文固定为:冻结 requirements、ID/coverage 摘要、当前模型紧凑测量、pending action 或最近动作摘要、最近一次相关错误、Runtime operation 名称。只在 LLM 调用 `inspect_topology` 后附带当前 selector token bank,只在调用 contract 后附带该 operation 的精确 schema。
4. 一次 LLM 回合最多执行一个 tool call;每个候选只允许一个 feature。此约束已经存在,必须保留。
5. tool 结果按结构化摘要持久化,prompt 只保留最新且仍与当前 `working_head` 有关的内容;历史完整证据在工件/账本中按需读取。
6. `batch_goal`、plan step/action 文本和 author `self_review` 从反复 prompt/调用中删除,改为服务端引用 pending action。
7. 记录每次 author/reviewer 调用的 provider `usage.prompt_tokens``usage.completion_tokens`(支持时)、序列化 context 字符数、工具名、重试原因和缓存命中。没有 usage 的 provider 使用 context 字符数作为次级指标,不伪造 token 数据。
验收指标以一组固定代表任务为准:矩形底板、简单法兰、带肋和安装孔的支架、含 selector 的修饰特征。与当前协议对比,目标是:
- 计划相关作者/审查调用降为零;
- 无失败的常规零件中,每一检查点只发生一次作者 fragment 调用和一次独立 candidate review
- 无副作用格式错误不进入候选构建、不创建 revision;
- 因内部异常产生的重复完成调用为零;
- 总 author+plan-review prompt tokens 的中位数下降至少 30%,同时完成率、最终复核通过率和几何断言通过率不低于基线。
30% 是初始验收线,不是凭空承诺。实现前须在现有协议上记录相同任务集的实际 usage,实施后以同一模型、温度、运行时版本和需求文本复测。
## 8. 实现范围与顺序
### P0:立即修复和回归(可直接实施)
- 保留已修复的 `_final_review` `global_violations` 初始化。
- 让未预期异常进入 `FAILED_INTERNAL`;不要走 `_fragment_diagnostic` 或增加 `no_progress`
-`complete_task` 加 revision-scoped idempotency,排除内部/基础设施错误对 `NO_PROGRESS_LIMIT` 的影响。
- 将 author transport fallback 改为有界状态机:每 provider 有限重试、最多一次 provider failover、全 run 总预算和指数退避;超限后进入 `WAITING_RETRY`,绝不保持 `running` 无限循环。
- 修复 modeling-plan revision-limit 的后检查控制流,直到 P2 完成前也不得出现“报上限后继续写计划”。
- 添加最小测试:最终审计全局不变量、内部错误只失败一次、同 revision 完成调用幂等、法兰四位置 `hole_blind` 单 feature 允许、贯穿孔拓扑断言。
### P1:文档先复核后冻结(可直接实施,独立于 P2)
- 建立 v3 `domain``application``ports``adapters` 包边界与 composition root;先迁移 requirements draft/review 这条窄路径作为样板。新增代码不得继续写入 `AutonomousCdslGenerationRunner`,也不得让 domain import 当前 services/engine/storage。
-`backend/requirements.txt` 显式加入并锁定兼容的 Pydantic v2 与 LangChain core / 已配置 provider integration 依赖;adapter 需要保留 `raw_arguments_json`(固定 schema 可使用 `with_structured_output(..., include_raw=True)` 或等价 raw tool-call 模式),不能只接收 LangChain 已解析的对象。依赖升级必须通过现有 API、timeout 和 usage 回归测试。
- 新增 Pydantic `RequirementsDraftBatch``RequirementsPatchBatch``RequirementsReview` 和空参数 finalize tool,由 `cad_agent/adapters/structured_llm.py` 的 LangChain adapter 调用,并在服务端原始 arguments 上二次验证。每 batch 最多 8 项,禁止 Markdown 写入工具。
-`TaskRepository``ArtifactStore` adapter 增加 source index、requirements JSON draft、requirements contract、review 和 render API;不得覆盖冻结 contract 或由 Markdown 反向读入状态。
- 实现 verifier registry、每种 claim 的 `expected` dynamic `oneOf` schema、registry integrity check 和 `requirements-contract.json` renderer;缺少 verifier 的可测需求必须明确失败。
- 在 runner 中替换“首次写入即 freeze”为结构化草稿状态机;复核失败有明确修改次数,达到上限时 `WAITING_FOR_USER`,不能无限重试或静默降级。
- 冻结 contract 后一次性生成 `requirements.md``completion.md``requirements-index.json`
### P2:以单动作协议替换建模计划(主要改动)
- 实现第 6.6 节的 finite state machine、typed command/result、port interfaces、Unit of Work、invocation idempotency、candidate staging/immutable publish 和 transactional outbox;先通过 domain/handler 测试,再接入真实 LLM、runtime 与 UI adapter。
- 新增固定 Pydantic `NextAction``GeometryConclusion``RollbackCheckpoint``CandidateReview``FinalReview``autonomous_tools()` 仅暴露第 4.7 节列出的严格结构化工具,移除 `write_modeling_plan``skip_satisfied_plan_step`、自由 `self_review` 和 plan 专属字段。
-`_author_tools()``_prompt_messages()``_execute_tool()` 拆为 context assembler、LLM turn coordinator 与独立 command handlercandidate metadata、coverage、repair 路径使用 pending action/ledger/claim result,不再读取或写入 modeling plan。handler 不得直接 import file/SQLite/provider/engine implementation。
-`profile_schema.json` 中的 feature contract 升级为完整 versioned operation contract registryauthor param JSON Schema、fragment shape、selector/reference policy、server injection、semantic-preflight 和 verifier binding 都由此处声明。删除 `cdsl_authoring_schema.py``cdsl_fragment.py``autonomous_cdsl_generation.py` 中按 operation 名称/前缀推断 params、selector 或默认 pattern source 的兜底规则。
- `submit_cdsl_fragment` 从完整 `feature_atomic_contract` 生成并绑定动态 schema;不得用一个宽松通用模型容纳不同 operation 的 params、sketch、selector、reference 或注入字段。schema 必须使用当前 snapshot 的 token enum,而不是任意 string 后补检。
- candidate/final 先执行 verifier registry,再调用结构化独立 review;`ReviewGateway` 接收 action card、claim IDs 和只读验证结果,而非 `plan_step`/`plan_action`。requirements review 是独立的 application command handler,不把它伪装成 completion Markdown review。
- `complete_task` 无参数;最终完成门检查所有 claim、pending action、repair 与最终复核。
- 增加 provider/model conformance suite 和 `model_capabilities` 持久化;不通过时禁止启动。
- 设计并实现 SQLite 状态层、账本 append 和幂等事务;文件工件由独立 `ArtifactStore` adapter 管理。
### P3:删除旧协议、API 和 UI
- 将任务 schema 直接升级为 `3.0`;不实现 `2.0` 迁移器、只读读取器或恢复逻辑。旧任务目录不由运行时扫描、打开或恢复,可在部署前由运维单独归档。
- 删除 `AutonomousCdslGenerationRunner` 的巨型实现及其 module-global helper 状态;入口仅负责 dependency composition 和发起 `WorkflowCoordinator`。旧 `WorkspaceStore` 不能继续同时是 repository、artifact store、task JSON writer 和状态机。
-`WorkspaceStore`、runner、API、前端类型和测试中删除 `modeling_plan_*`、plan step/action、`write_modeling_plan``skip_satisfied_plan_step` 及其 Markdown parser/reviewer。新协议中不得保留隐藏 fallback、遗留 tool 参数或分支。
- `GET /v1/tasks/{id}` 和前端 `cad-types.ts` 替换 modeling-plan 字段为 requirements contract/review、claim summary、pending action、action ledger summary 和 protocol version;不再有 completion Markdown review 字段。
- `agent_service.py``cad-stream.ts` 删除“建模计划 / 计划独立复核 / 计划步骤已满足”事件,增加“需求合同独立复核 / 动作选择 / 候选独立复核 / 最终独立复核 / 动作账本”事件。
- 前端显示事实和状态,不能把 ledger 误显示为 LLM 的未来计划。
### P4:验证与发布门
- 单元:所有固定 Pydantic model 的 valid/invalid fixtures、每个 Runtime operation 的动态 schema fixture、operation mismatch、stale head、selector ambiguity、single multi-position hole、through topology、每个 verifier、ledger/transaction/idempotency、typed errors。
- 架构:domain transition table 的全部合法/非法状态边、每个 command handler 的纯 result、port adapter conformance、dependency-rule test、SQLite CAS 冲突、staged artifact crash recovery、outbox 至少一次投递与消费者幂等;不得依赖端到端 LLM run 才发现状态机错误。
- 集成:每个配置 provider/model 的真实 conformance suite;实现过程中按第 6.7 节调用真实 LLM `smoke`,并在完成前由 Codex 实际执行 `python -m app.cad_agent.evals.live --suite release --require-live`。release 报告必须保存匿名化调用指标与工件路径;分别覆盖成功、格式拒绝、候选拒绝、verifier fail、review service 失败、内部异常。任何 `LIVE_EVAL_BLOCKED`、skip、预算超限或场景失败均阻止发布,不能以 mock/integration test 替代。
- 回归:全量 `backend` 测试、前端类型/stream 测试,以及不识别旧任务 schema 的拒绝测试。
- 发布:一次性切换到 v3;部署前停止旧 worker 并归档旧任务目录。上线后删除 v2 plan 生成路径、parser/reviewer 和全部关联测试,不保留 feature flag 双轨或历史工件读取能力。
## 9. 主要代码触点
| 位置 | 必须修改 |
| --- | --- |
| `backend/app/services/autonomous_cdsl_generation.py` | 删除巨型 runner 的业务实现;迁移期间只可作为入口 shim,v3 发布前移除,不能继续承载状态、CAD、LLM、文件和复核逻辑 |
| `backend/app/cad_agent/domain/*.py`(新增) | 不可变 task/action/revision value objects、workflow state/transition table、operation/claim policy、typed domain result/error;无任何 I/O import |
| `backend/app/cad_agent/application/*.py`(新增) | command schemas 到 domain command 的转换、command handlers、workflow coordinator、context assembler、Unit of Work 使用;不直接依赖 adapter 实现 |
| `backend/app/cad_agent/application/llm_contracts.py`(新增) | Pydantic v2 固定 LLM input/output DTO;只负责 schema,不包含 persistence、Runtime 或 transition 规则 |
| `backend/app/cad_agent/ports.py`(新增) | `TaskRepository``ArtifactStore``ModelGateway``CadRuntime``ReviewGateway``VerifierExecutor``EventPublisher` 等 Protocol 与 typed failure contract |
| `backend/app/cad_agent/adapters/*.py`(新增) | SQLite/file、CDSL engine、render/review、provider、outbox 的 port 实现;所有外部异常在此映射为 typed adapter error |
| `backend/app/cad_agent/adapters/structured_llm.py`(新增) | 唯一 LangChain provider adapter;固定 Pydantic 和动态 JSON Schema 调用、原始 arguments 捕获、canonical 二次验证入口、provider capability mapping;不含 CAD 状态机 |
| `backend/app/cad_agent/evals/live.py``backend/app/cad_agent/evals/fixtures/*.json`(新增) | 非交互真实 provider/engine/reviewer release runner、版本化场景/预算/claim fixtures、隔离 SQLite/artifact root、脱敏 report/manifest`--require-live` 时任何 skip 或 fake adapter 都必须失败 |
| `backend/requirements.txt`(及实际使用的 lock file | 显式 Pydantic v2、LangChain core 和对应 provider integration 的兼容范围;不能依赖 FastAPI 间接安装的 Pydantic 版本 |
| `backend/app/cad_agent/application/requirements_review.py`(新增) | 结构化 requirements review command handler、coverage gate、draft patch feedback;不解析或写入 Markdown |
| `backend/app/cad_agent/domain/verifier_registry.py`(新增) | claim schema registry、contract integrity、针对 typed verification facts 的纯 deterministic evaluator;启动时拒绝不可用 verifier |
| `backend/app/services/cdsl_authoring_schema.py``backend/app/services/cdsl_fragment.py``backend/engine/cdsl_engine/profile_schema.json` | 迁移为 `CadRuntime` adapter 的完整 versioned operation contract、dynamic fragment schema、selector/reference resolver、semantic preflight;删除按 atomic ID 的重复/开放式 author schema 和默认 source 注入 |
| `backend/app/services/storage.py` | 拆分为 SQLite `TaskRepository`/`UnitOfWork` adapter 与不可变 `ArtifactStore` adapter;加入 invocation、state version、candidate staging manifest、ledger index、outbox;删除 task.json 权威状态和 v2 兼容 |
| `backend/app/services/visual_review.py` | 迁移为 `ReviewGateway` adapteraction-based candidate/final review,不再承担 requirement 或 completion Markdown review |
| `backend/app/services/agent_service.py` | delivery/worker adapter,只启动 `WorkflowCoordinator`、记录 usage 并消费 typed result;不得重试内部失败为 author turn |
| `backend/app/settings.py` | protocol version、文档修订上限、action/context/usage 配置;删除 plan 配置 |
| `backend/app/main.py` | API 输出 v3 文档审核和动作账本摘要 |
| `frontend/src/lib/cad-types.ts``frontend/src/lib/cad-stream.ts` | 新事件与字段,删除 plan 特有状态 |
| `backend/tests/*``frontend/src/lib/*.test.ts` | 删除 v2 plan 行为测试,新增 P0-P4 回归 |
## 10. 需要确认的架构决策
以下是本目标已作出的绑定选择,不留作实现期间临时决定:
1. **采用 SQLite 作为 v3 可变状态的唯一权威来源。** 当前 `task.json`/`agent-state.json` 的文件读写无法为 checkpoint、pending action、幂等调用和 ledger append 提供真正的原子事务。保留 JSONL 账本和文件工件,但它们不是可变状态源。代价是 `WorkspaceStore` 持久化层重构;这是达到可靠性目标的必要改动。
2. **不兼容旧任务。** 不应把已有 `modeling-plan.md` 任务转换为 pending action,因为无法无歧义地映射历史计划状态;v3 运行时只识别新协议工件。
3. **建议把无法可靠消除的需求歧义显式置为 `WAITING_FOR_USER`。** 对“简单法兰”一类可合理假设的请求,LLM 仍可写明假设并继续;只有冲突、关键基准/尺寸导致多种同等合理且会明显改变模型的情况才暂停。
4. **采用第 6.6 节的六边形边界和显式状态机。** 这不是可选重构或文件整理;不允许以“赶进度”为由把 Runtime/LLM/SQLite 直接重新接回 workflow handler。
## 11. 非功能验收
实现完成时必须能证明:
- 法兰任务不会因 `global_violations`、重复 `complete_task` 或 plan revision limit 失败;最终复核若故障,任务保留 `rev_003` 类的最后健康 checkpoint 和精确错误类别。
- LLM 看到 requirements、coverage、当前模型和账本摘要后,自己提出“下一动作”;服务端日志可证明它没有自动替 LLM 推导该动作。
- `hole_blind` 的四个同宿主位置作为一个 action/feature 通过,中心/螺栓通孔通过最终 topology 断言而非仅靠盲孔深度文字。
- 任意 action proposal 或 CDSL 格式错误均不产生 revision、不改变 active head、不消耗候选构建预算。
- 每个接受的 checkpoint 都能从 ledger 追到 author intent、真实 atomic/fragment hash、selector snapshot、独立复核和 coverage 证据。
- 静态 dependency-rule test 证明 domain 不导入 FastAPI、LangChain、SQLite、文件、engine、render 或 settingsapplication 不导入 adapter 实现。状态迁移只存在于 domain transition table/command handlerAPI、stream、adapter 和 reviewer 均不能直接写任务状态。
- 进程在 candidate build、artifact publish、SQLite commit、outbox dispatch 或 stream publish 的任一点终止后,恢复测试均证明:系统要么保留原 checkpoint,要么通过同一 invocation/manifest 完成一次提交;不会出现公开半工件、双 revision、重复 build 或丢失已提交 ledger event。
- 所有会改变状态、影响 CAD 执行或作为验收依据的 LLM 输出均对应第 4.7 节的一项 canonical schema,并在状态变更前通过 schema、state binding 和适用的 domain validator;不存在 Markdown/自由文本/开放 object 的旁路。
- 每个 Runtime operation 均通过完整 contract integrity、valid/invalid dynamic-schema fixture、selector/reference snapshot、semantic preflight 和 engine-execution 测试;缺少参数、无参数、草图、非草图、required/forbidden selector 和 nested option 的差异均由 schema 而非 prompt 表示。
- task 开始前,选定 provider/model 在全部固定 schema 与每个已注册 dynamic operation schema 的真实 API conformance suite 中通过;未通过只报 `MODEL_STRUCTURED_OUTPUT_UNSUPPORTED`,不允许回退为自由文本。
- 实现目标的 Codex 已实际运行第 6.7 节的无 skip `release` 命令,使用当前配置的真实 author/reviewer 模型、真实 CAD engine 和 v3 状态机完成固定任务集三次重复;结果报告和工件 manifest 可定位,且没有 `LIVE_EVAL_BLOCKED`、失败场景、预算超限或隐藏的 schema/decision rejection。
- 发布前全部 deterministic claim 必须以当前 revision 的程序化 evidence `pass`LLM review 只作为 visual/语义的独立补充,永远不能覆盖 `fail``unavailable`
- P4 固定任务集给出实施前后真实调用指标,满足第 7 节的可靠性及 token 目标。