Commit Graph

11 Commits

Author SHA1 Message Date
iomgaa c5c1e68706 docs(design): 按两轮硕士生冷读改 0009 与 0010
0009 最实的一条是文档与代码对不上:文档说那条扫描测试断言 __dataclass_params__.kw_only,
而代码实际查的是构造签名。冷读的人正确地指出前者守的范围更窄——哨兵写法 KW_ONLY 达成了同样
的效果但那个标志是假(会误杀),而 kw_only=True 的类里用 field(kw_only=False) 开口子那个
标志仍然是真(会漏掉)。文档改成描述实际做法并写清楚这条理由。另修:「长六个字符」实际是
五个;补上两种写法的区别、Pydantic AI 那条「超过一个位置参数」与本文「一个都不许」的差别
来自处境不同、规则作用域只管数据类(NamedTuple 与 pydantic 绕得过,是已知边界)、
以及 §1.3「新增字段必带默认值」为什么不受影响。

0010 最实的一条是论据自相矛盾:决策二拿「跑通了的下游逐字一致」当段序依据,决策三又说那个
槽位在那边至今没实现、收到非空注入直接抛错。改成说准——它证明的是有人设计装配顺序时把槽位
放在了这里,不是这个位置在真实提示词里验证过。另补一节「读本文需要的几个名字」(注入/通道/
解释器/合成观察/四者同源/pi 全是首次出现即使用,而且「Skill 条目」「工件」「Injection」三个
说法指同一样东西却没有一处对上);承认库实际还定了消息边界的粒度,超出了「只管顺序槽位规模」
那句话,并给出这条线画在哪的判据;说明「变化频率」指的是跨运行而不是一次运行内部;补上规模
量出来给谁用、模板为什么在构造请求时就校验、以及为什么不回填解释出来的动作。
2026-08-10 03:15:46 -04:00
iomgaa 2367d3afbc feat(_assembly): 落成段序与注入槽;design 0010 删掉工具段模板
0010 取代 0006 决策三里 tool_section_template 那一行。三条理由:两个真实消费者都是项目侧
自己把工具清单拼进上下文的(一个塞在 run 级模板里伪装成示例演示的一次执行输出,另一个的
render_tool_docs 全仓零生产调用方);留着它的话迁移的人会去填,填完提示词里有两份工具清单,
而那个下游的验收标准是轨迹逐字段可比、变了还不报错;参考框架 pi 的内核同样不渲染,它的应用层
虽有 Available tools 段,但每行来自与 description 分开的 promptSnippet 字段——说明就算要渲染,
那段文字也不该是从校验用的 schema 生成的。四者同源不受影响,schema_for_model() 还在。

段序照唯一跑通了的下游:run 级片段 → 注入槽 → 目标级片段 → 逐步的模型输出/观察交替,
按变化频率从低到高排(供应商按前缀缓存计费)。库不合成任何 system 消息——有一个下游全程
没有 system 消息,加一条它的提示词会凭空多出一段。

注入槽每条一条 USER 消息、正文原样、不加任何分隔符(分隔符是渲染格式,归项目侧),通道按
名字排序(映射的迭代顺序取决于调用方怎么构造,用集合建出来的每进程都不同)。空注入等同有
测试守着。观察模板必须含占位符,缺了就报错——不校验的话每一步的观察会整个消失,而模型收到
的是一段看起来完全正常的固定文本。规模度量逐块问,认不得的块类型直接失败而不是当成 0。

零业务假设扫描第三次抓到我自己(模块 docstring 里写了「实验因子」),已改成中性说法。
migrations/govdoc-saas.md 登记了「模型原生工具调用没有路」这个缺口。
2026-08-10 02:48:56 -04:00
iomgaa 7da5e07726 docs(design): 给 0008 与 0009 补上外部先例,两个决定都是印证不是改动
0008:主流框架没有一家把截断量做成工具返回值上的字段(Anthropic 的 tool_result 只有三个
字段,OpenAI/LlamaIndex/Pydantic AI 的结果类型都没有),唯一结构化记下来的 LangChain 走的
是通用 artifact 通道而不是专设字段。另补「将来要加时怎么加」的正反两例:Pydantic AI 在允许
返回的类型集合里加一个新类型、旧路径不动,零兼容问题;OpenAI Agents SDK 改成运行期形状
嗅探,一个返回 {"msg": ...} 的普通工具被当成图片输出转掉、线上 400,三天后回落。

0009:Pydantic AI 2026-07 加过一条几乎同形的 meta-test(扫描包、新增公共数据类超过一个位置
参数就失败),PR 正文两句正好对上本文两条论证——「一条老在评审里被提却没有机器执行的意见」,
以及「不给已有的数据类补,那会打断按位置构造的调用方;白名单只减不增,清空它得发新 major」。
它已经付了本文想避开的那笔账。另记一条连带影响:kw_only 字段不进 __match_args__。
2026-08-10 01:21:12 -04:00
iomgaa 6fafd95d6c feat(tools): 落成 executor() 与派生分发器;公共数据类一律只收关键字参数
两个自行调研后决定的问题,各自的证据写进了 design doc:

一、handler 返回 str 而不是带截断计数的小结构(0008 决策三,文末新增一节)。三条实据:
两个真实消费者的执行函数今天就返回纯字符串(GovDoc 的 handler 是 Coroutine[..., str],
dissect 的环境 execute 是 -> str);dissect 的 observation_truncated_chars 唯一的生产写入点
硬编码 0 且全仓零读取点,存在的是名字不是需求;reference/pi 是唯一把截断做完整的,它记的是
totalBytes/outputBytes/maxBytes 这组绝对量而不是一个差值——现在补 truncated_chars 补的
大概率是错形状,正是 scope.md 说的「猜出来的接缝比没有接缝更难拆」。

二、新增 design 0009:src/polyloop/ 下每个数据类都加 kw_only=True,另加一条扫描测试守它。
实验室七个仓库 223 个 dataclass 里 kw_only 出现零次,但那是默认行为不是选择。真正的证据是
PolyGateway:它的 LLMResponse 前 11 个字段顺序被三个下游的测试替身按位置构造锁死,模块
docstring 写着「字段顺序即公共承诺」,还得专门写一条 test_eleven_legacy_fields_positional
守着,从此再也插不进字段。那个约束不是它选的是它继承的,而本库还没有下游装上。
扫描测试查的是构造签名不是那个装饰器参数——要守的承诺是「按位置构造不了」。

executor() 在派生那一刻全查一遍实现,缺一个就报错,不拖到分发时才炸。RegistryExecutor 是
具体类而不是闭包,因为 RunRequest 要用 isinstance 认它。CancelledError 不被那个
except Exception 接住(它继承 BaseException),有测试守着。
2026-08-10 01:19:15 -04:00
iomgaa 4bf74bf5ac feat(_stopping): 落成停止判定四档,0008 转已接受
四个纯函数各管一档,顺序本身由主循环走:预算准入(A)、提示词规模(B)、连续解析失败(D)、
完成判定(G)。加一个不可变的三计数结构。

三处刻意钉死的边界,都写了测试:
- 两个预算上界同时耗尽报步数那一个。理由是兼容性不是原理(某下游按步数耗尽的占比告警),
  正因为推不出来才必须被测试钉死。
- 预算「达到即拦」用 >=,提示词规模「超过才拦」用 >。两处不是同一件事:一个数已经用掉
  几个额度,一个量一个东西有多大。
- 环境故障排在完成判定前面;未执行不做完成判定;完成信号恒为假不是故障(初稿在这里
  写错过,会让某个下游的每一次运行都在第一步终止)。

不 import polyloop.tools,五个逻辑层模块互不 import,所以「这次执行的工具被标了完成标记吗」
由调用方查好注册表传一个布尔进来。
2026-08-10 01:04:38 -04:00
iomgaa 956d98652d fix(tools): 修掉两个假阳性与一个改得动的内部状态,按两轮独立评审
代码审查(新鲜上下文,只给 diff 与验收标准)报了五条影响正确性的,逐条核实全部成立:

1. spec_for() 交出去的 parameters 就是注册表内部那份真字典。docstring 承诺的快照只挡住了
   「调用方改自己那份」,没挡住「从注册表取出来往里伸一层改」——而后者一下同时改掉模型
   看见的 schema 和校验用的 schema。改成逐层冻成只读视图,schema_for_model 出口再化回
   普通字典与列表。
2. {type: integer} 拒掉 3.0。JSON Schema draft-06 起小数部分为零的浮点数是合法整数,
   模型写 1e2 时 json.loads 给的就是 float。这是我自己在注释里点名最怕的那种假阳性。
3. additionalProperties: false 撞上 patternProperties 时拒掉一切匹配 pattern 的键。
   那些正是这份 schema 专门要收的键,模型改名也绕不过去。patternProperties 在场就跳过。
4. 工具名不校验类型、纯空白名放行。名字要落进发给模型的 schema,不是字符串会让整个请求
   被网关拒掉,报错指向请求体不指向注册表。
5. _by_name 是可变 dict,两条查询路径能被就地改到分岔。换成只读视图。

不可哈希那条不修,改在 docstring 里写明(参数 schema 是映射,注册表放不进 set)。
scope.md 的行号引用换成条目名——行号是最容易漂的一种参数,插一行就静默指错。

0008 按一轮硕士生冷读重写:字段位置那段原来自相矛盾(一边说位置是公共承诺、插在中间会
静默改掉后面字段的含义,一边就插在中间,且没讨论追加在末尾这个同一判据下的显然选项),
改成追加在末尾并说明规则;补上四个名字的就地解释(重放策略、两条完成通路、动作结果五个
字段、restrict_to);决策四那张表原来只有三列却被正文说成填五个字段,恒定的两个单列出来
并各自给了理由;补上 validate 不通过为什么算未执行、executor() 为什么全查、为什么必须是
具体类而不是闭包、异常栈去哪了。
2026-08-10 00:57:36 -04:00
iomgaa 77ffad9dc4 docs(design): 落成 0008,补上工具实现挂在哪里这个洞
0006 决策六定的 ToolSpec 五个字段里没有一处装工具本身的实现,注册表派生的执行器
拿到一次合法调用之后无处分发。handler 这个词只在 0003 的正文里出现过,从没写成字段。

本文定四件事:实现挂在 ToolSpec 上(不另开清单,防漂移)、可以为空但 executor()
那一刻就查、签名是收参数返回观察文本的协程、派生执行器怎么填 ActionOutcome 五个字段。
状态待确认,要过 CLAUDE.md §2 人类门。
2026-08-10 00:45:40 -04:00
iomgaa f8e02290f4 docs(design): 落成 0006 与 0007,公共 API 的名字、签名与接缝行为
0006 定「叫什么、什么形状」:五个接缝的 Protocol 名与签名、公共类型的英文名与
字段清单、类型分到 types / ports / tools 三个模块的判据。
0007 定「同一个签名下什么算对」:三个动作状态的触发条件、动作被拒绝时观察由库
合成而不取执行器那段、解释器不许抛异常、read_log 读不存在的运行返回空日志。
两份拆开是因为后者的权威处按 §0 是 tests/contract/,design doc 只记当初为什么这么定。

这两份改动了 0003 四处,全部在文首登记:记录集合是六种东西不是五类;
参数视图是方法不是字段;预算是四项不是两个计数;ports 装「Protocol 与它们的
入参/返回结构体」那半句写不出来——照它写 types 会反向依赖 ports。
四处全是「把字段类型逐个写出来」这个动作本身逼出来的,纯读文档看不见。

四轮评审:两轮硕士生冷读报了约 45 条,两轮 Codex 对抗审查报了 13 条,
逐条核实后基本全部成立并修完。最后一轮是唯一一次契约测试与文档互相抓到对方的错——
文档改了方法名测试没跟,测试把 dissect 的动作语言写死成输入会误杀 GovDoc 的实现。

结论回写 architecture.md:第七节补类型归属判据,第八节改 ports 那一行,
第九节补五个 Protocol 的英文名,第十四节把「英文名还没定」那条缺口换成指向;
决策索引加两行。字段表刻意不回写——按 §0 那是代码的权威。
CLAUDE.md 与 README.md 开头的「一次 Agent Session」是术语漂移,改成「一次运行」。

CLAUDE.md §7 加两条工作方式:能压成一段结论的活尽量交给 subagent、
委托出去的活交证据不交判断;以及持续往下做,只在人类门和真判断不了的岔路停。
§8 那句「讲完停下来等回应」与后者打架,收窄到只管说话方式。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 23:56:38 -04:00
iomgaa 766f7a0290 docs(design): 落成 0005,修订存储接缝的原子写与步记录三处
第二轮 Codex 对抗审查报的五条全部核实成立,0003/0004 已冻结,修订新写一份。
五条都不改任何决策的结论,改的是结论到形状之间那一段的落实。

决策一:步记录加一个布尔的完成信号列。0004 决策二承诺靠它区分两条完成通路,
而决策四的字段表里没有这个字段。它自己就够区分,不必查注册表——
事后分析手上常常只有轨迹文件。
决策二:存储接缝六个方法重切一刀,把「按预分配 ID 写一条结果」拆成
「写模型调用结果」与「写动作结果与步记录」。原子性从散文变成签名里不可表达其他形态。
决策三:观察那一列的口径改成「回填进历史的那段文本」,不加字段。
dissect 的 render_messages 把 step.observation 原样套模板发出,
raw_output 也是解析器截断后的版本——两侧同构,都是一段文本加一个数字。
决策四:作废 0004 词表里「一个可能取不到的完成信号」,那是上一轮 fatal bug 的原话。
决策五:存储接缝加前缀持久性。少了它,一次明明成功的模型调用会被恢复
记成「状态未知」,而它成功的证据就在同一份日志里。

结论已回写 architecture.md 第九节与决策索引;migrations/dissect.md 需求七
补上「分开记的是文本加数字,不是两段文本」,堵掉这次审查里出现过的误读。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 12:02:38 -04:00
iomgaa 4f8812fa82 docs(design): 落成边界、续跑、公共 API 形状与停止语义四份决策
第 ② 阶段需求对齐与第 ③ 阶段架构的产出,代码尚未开始。

design/0001 定边界判据:三道测试(时机 / 信息 / 性质)全过才在界内,
外加「只认接缝、不认接缝后面是什么」与不夺走下游实验因子的排除条款。
design/0002 定步级续跑:不承诺原子性,承诺绝不静默丢失与不替工具猜幂等性;
先写意图再执行、结果 ID 预分配、重放策略由工具声明且默认绝不重放。
design/0003 定公共 API 形状:单一入口两个动词、五个接缝、三个伪接缝的排除理由、
分层与九条依赖规则。design/0004 定停止判定顺序、十个停止原因取值与步记录字段表。
0003 与 0004 需过 CLAUDE.md §2 人类门,已由项目负责人确认,状态转为已接受。

explanation/scope.md 与 explanation/architecture.md 是这四份决策的常青回写,
分层与模块边界的权威在 architecture.md,将来由 import-linter 契约机器断言。
migrations/ 下 dissect 是唯一的硬迁移验收,govdoc-saas 只做设计级对齐。

三道闸都过了:14 agent 对抗辩论定骨架,两轮硕士生阅读报的 30 余条已修完,
Codex 对抗审查抓出的两条致命问题(提交型完成被误判成环境故障、
崩溃恢复漏一个状态)已修,修完的形状还没送 Codex 复审。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 10:48:33 -04:00
iomgaa a2e94318b9 chore(repo): 建仓,落成协作规范与文档骨架
协作方式以 CHSAnalyzer 为蓝本,按「库」这个身份改写:

- CLAUDE.md §0 的权威表换成公共 API 契约、公共类型、下游迁移三条主线,
  数据库 schema / HTTP 契约 / alembic 迁移在本项目不存在,整体删去。
- §1 新增四条库特有的硬约束:字段只增不删不改名、持久化 schema 走显式版本、
  不反向 import 下游、发布必须走完整流程(PolyGateway 有两个版本只 bump
  没上传,registry 长期停在旧版且无人发现)。
- §3 的四类 Codex 对抗审查按同一判据重定:公共签名、停止判定与预算结算、
  取消传播与 Session 隔离、schema 演进。共同点是错了不会当场炸。
- research-wiki 在常青层加第四类 migrations/,因为本项目的核心验收标准就是
  能否搬回 dissect、能否替代 GovDoc-SaaS 的 docagent-core/,塞进 guides/
  会让它看起来像可选工序。

reference/ 不入库:五个仓库各带一个 .git、合计约 96MB,提交进来会变成一堆
不可用的嵌套仓库。它也不是任何事实的权威,agent-core.md 同理。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 07:02:09 -04:00