audit: lifecycle hook writes the attempt ledger (gap 3 follow-up)
- cloud/attempt_hook.py (new): canonical policy -- one counted dispatch = one row, is_defect always False from the worker; human/first rounds and human breakpoint resumes count; platform auto-resume reruns, coordinator fan-out, and pre-execution gate failures do not; transient retries inside one dispatch are not new attempts. Platform origin survives via the task_attempt_origin_markers table (same-transaction write on requeue, queued_at generation guard on consume). Defects are explicit-recorder only; corrections are append-only (record_correction, last-wins). - cloud/worker.py: Worker(attempt_ledger_hook=False) + CLI --attempt-ledger-hook (default OFF = gap-3 behaviour exactly); marker write in auto_resume_interrupted, marker consume + classify in run_one, one ledger write at each terminal point (cancel branch, normal terminal block); all hook writes best-effort, never fail the task or block a requeue. - cloud/attempt_ledger.py: corrects_attempt_no column (new DDL supersedes gap 3's pre-merge DDL) + record_correction + correction-aware aggregation; read path uses SELECT * so gap-3-era tables still read; cost code untouched. - cloud/tests/test_attempt_hook.py: 32 tests (policy, markers, corrections, worker integration, mixed endpoint). - docs/arch-conformance-metrics.md: policy, switch, PG manual steps (new PG_DDL + PG_MARKER_DDL), remaining user decisions.
This commit is contained in:
1 parent
436a92ba1d
commit
dc556b0c19
5 files changed
+1522
-38
No files matched your search
@@ -60,8 +60,10 @@ workflow——第 2 轨拥有 lint/类型/安扫,本轨不碰。
|
||||
`cloud/attempt_ledger.py` 模块 docstring 里。
|
||||
|
||||
表 `task_attempts(task_id, attempt_no, outcome, is_defect,
|
||||
defect_category, created_at)`,主键 `(task_id, attempt_no)`,
|
||||
`attempt_no` 按任务 `MAX + 1` 递增、只追加不改写。口径:
|
||||
defect_category, created_at, corrects_attempt_no)`,主键
|
||||
`(task_id, attempt_no)`,`attempt_no` 按任务 `MAX + 1`
|
||||
递增、只追加不改写(`corrects_attempt_no` 为 NULL 时是真
|
||||
尝试行,非 NULL 时是纠正行,见钩子一节)。口径:
|
||||
|
||||
- `outcome` ∈ success / failure / interrupted;`interrupted`
|
||||
行只留档,不计入 attempts 也不计入 defects(平台中断自动
|
||||
@@ -82,13 +84,81 @@ defect_category, created_at)`,主键 `(task_id, attempt_no)`,
|
||||
PG,真实 PG 验证未做;PG 证据目前只有适配层级别:`?` 占位
|
||||
经 `cloud.db` 适配翻译为 `%s`、DDL 无需序列处理(测试
|
||||
`TestPostgresAdapterEvidence` 钉住)。
|
||||
- 未做项(有意不做,原因见模块 docstring):生命周期写
|
||||
入钩子未接——worker 重试/续跑循环里哪一次算一次尝试、谁
|
||||
判定 `is_defect`,接错会把平台自动续跑算成尝试、把瞬时
|
||||
重试算成缺陷,正好违反本轨钉住的规则;在此之前台账只
|
||||
经显式 `record_attempt` 调用填充,生产率在写钩子落地前
|
||||
保持诚实未知,不自动填数。读端点不建表(只读端点不改
|
||||
schema),建表只发生在写路径。
|
||||
- 生命周期写入钩子已接(9+ 第 2 项,见下一节):worker
|
||||
按政策给计数的派发写且只写一行,开关默认关;关时台账
|
||||
仍只经显式 `record_attempt` / `record_correction` 调用填
|
||||
充,生产率保持诚实未知。读端点不建表(只读端点不改
|
||||
schema),建表只发生在写路径;标记表同理,只在钩子开
|
||||
且平台自动续跑发生时写。
|
||||
|
||||
## 任务尝试生命周期写入钩子(9+ 第 2 项,政策与开关)
|
||||
|
||||
权威政策在 `cloud/attempt_hook.py` 模块 docstring(代码、
|
||||
本文档、测试三处一致,冲突时以模块为准)。要点:
|
||||
|
||||
- 计为一次尝试的(每派发恰好一行,`is_defect` 恒
|
||||
`False`):任务首派发;人工 `/retry`(与首派发无法区分、
|
||||
也不必区分,两者都算);人工 `/continue` 新消息轮次
|
||||
(含开新目标循环的 goal 任务);人工断点续跑
|
||||
(`/goal-resume`、旧验收 goal 的 `/continue` 断点语义)
|
||||
——断点续跑算同一逻辑轮次的行,不是额外尝试:被中断
|
||||
的片段只写了不计数的 `interrupted` 行,续跑终局行就是
|
||||
该轮次唯一计数行;续跑再中断则仍只写 `interrupted`
|
||||
行,该轮次继续保持未知。
|
||||
- 不计为尝试的(不写行):平台自动续跑派发(goal 断点续
|
||||
跑与非 goal 全新跑一律不计——统一口径,平台杀掉又重跑
|
||||
的执行不罚 agent 质量分);协调员父派发(只做扇出聚
|
||||
合、无模型回合,子任务各自写行);执行前门失败(缺
|
||||
key / 仓库解析 / 配额门 / 轮次上限 / 网关准备,准入拒绝
|
||||
不是尝试);未派发(预算门、无就绪任务、认领输给别的
|
||||
worker,连分类都不跑)。
|
||||
- 同一派发内的瞬时重试不是新尝试:`max_retries` 循环、
|
||||
一次真实 fallback 换模型重跑、goal“已存在”断点回落、
|
||||
后续消息排空都在一次 `run_one` 里,共享成本汇总、只
|
||||
产一行(终局 outcome)。内层失败后重试成功不留失败
|
||||
行;重试耗尽只留一行失败行。
|
||||
- 平台识别靠标记表 `task_attempt_origin_markers`:自动续
|
||||
跑在同一事务里写标记(`queued_at` = 重排队写的
|
||||
`updated_at`),认领方在认领前抓排队态 `updated_at`、
|
||||
认领成功后按 `queued_at` 匹配消费;人为动作(取消/
|
||||
重试/继续)改写 `updated_at` 后陈旧标记自动作废,绝不
|
||||
误伤后一轮人工派发;认领输了不消费,标记留给赢家。
|
||||
标记写失败绝不挡重排队(退化为计数,见模块规则 5)。
|
||||
- 开关:`Worker(attempt_ledger_hook=False)` / CLI
|
||||
`--attempt-ledger-hook`,默认关。关时 worker 不写任何
|
||||
台账行、不写标记、不建台账/标记表,与补缺口第 3 项行
|
||||
为完全一致;开时才适用本节政策。开前中途(钩子关时已
|
||||
重排队的任务无标记)有一次性的退化:该派发按人工/首
|
||||
轮计数,之后每次重排队都有标记,即自愈。
|
||||
- `is_defect` 判定主体:只有显式记录方(人工维护者或协
|
||||
调员复核)在记录时判定,worker 钩子永不判定(失败 ≠
|
||||
缺陷,瞬时失败尤其不是)。标错只追加纠正行
|
||||
(`record_correction`:新行 `corrects_attempt_no` 指
|
||||
向原尝试,旧行不动;聚合按 attempt_no 顺序后赢者通
|
||||
吃;纠正行本身不计尝试、不能改 outcome、不能指中断
|
||||
行/纠正行/不存在的尝试,违例写时 `ValueError`)。
|
||||
维护者门槛与 `/retry` 同款(`approve_merge`),但本轨
|
||||
不建标记/纠正的 HTTP 端点(函数即接口,端点是后续项,
|
||||
见未做项)。
|
||||
- 取舍(明写):仅经平台派发终局的任务在台账里保持未
|
||||
知(无计数行),分母只含人工/首轮终局的任务——率值描
|
||||
述的是“人工/首轮终局任务”,不是全部终局任务;平台重
|
||||
跑本身未丢失(`auto_resume_count`、审计
|
||||
`worker_auto_resumed`、时间线 `auto_resume` 行)。被拒
|
||||
的替代方案是“单独标记平台行但不进分母”:分母结果相
|
||||
同,但多一种行、多一列、多一套聚合排除逻辑,只换来
|
||||
台账内同址可查——本轨不取。另:平台 goal 续跑与人工
|
||||
goal 续跑同属一轮循环,但前者不计、后者计(标记优于
|
||||
断点),这是有意的统一平台排除;若用户要把平台 goal
|
||||
续跑也算作轮次完成,改 `classify_dispatch` 一行 + 测
|
||||
试即可,属用户拍板项(见待人工项)。
|
||||
- Postgres:标记表与台账表同款手动纪律——不进
|
||||
`POSTGRES_SCHEMA`,`PG_MARKER_DDL`(与台账新 `PG_DDL`
|
||||
含 `corrects_attempt_no` 列)须在生产 PG 上手动执行并
|
||||
验证后,才可在 PG 控制面启用钩子;未执行时标记写失
|
||||
败(best-effort),平台派发退化为计数。本机无 PG,真
|
||||
实 PG 验证未做;PG 证据只有适配层(`?`→`%s` 翻译、
|
||||
DDL 无自增/identity 列,测试钉住)。
|
||||
|
||||
## 回流与审计标准迭代(可测试规则,非口号)
|
||||
|
||||
@@ -138,7 +208,18 @@ defect_category, created_at)`,主键 `(task_id, attempt_no)`,
|
||||
|
||||
待人工项(单独列):金任务集审定清单的四项人工确认;抽查 seed
|
||||
的记录与保管;生产抽查比例拍板(默认值 0.10/0.50 只是测试初值)。
|
||||
台账待人工项(补缺口第 3 项之后):生产 PG 上手动执行
|
||||
`task_attempts` 的 `PG_DDL` 并验证;生命周期写入钩子拍板——
|
||||
哪次执行算一次尝试、谁判定 `is_defect`(在拍板前台账只经
|
||||
显式调用填充,生产率保持未知)。
|
||||
台账待人工项(钩子落地之后):生产 PG 上手动执行台账新
|
||||
`PG_DDL`(含 `corrects_attempt_no` 列;若曾跑过补缺口第 3
|
||||
项的旧 DDL,先跑 `OLD_TABLE_ALTER`)与标记表
|
||||
`PG_MARKER_DDL` 并验证(`\d task_attempts` /
|
||||
`task_attempt_origin_markers` 或 information_schema 等价查询),
|
||||
验证前不在 PG 控制面启用钩子;钩子政策默认值拍板——平台
|
||||
goal 续跑不计(本轨默认)还是计为轮次完成、平台非 goal
|
||||
全新跑不计(本轨默认)是否接受、缺陷标记/纠正的 HTTP
|
||||
端点(`approve_merge` 门)是否立项;金任务集审定后报告才
|
||||
可决策(现仍恒为 `pending_human_approval`)。
|
||||
未做项(本轨有意不做):缺陷标记/纠正的 HTTP 端点(函数即
|
||||
接口,权限检查随端点做);worker 之外的写行点(服务端
|
||||
`/retry` / `/continue` / `/goal-resume` 本身不写行——写行
|
||||
只发生在 worker 派发终局,服务端重排队不直接产生尝试);
|
||||
真实 PG 验证(本机无 PG);生产部署(只到 PR OPEN)。
|
||||
Reference in new issue
Block a user