ThearchyHelios
c549b15150
合入期 4 期 3 收尾:核查缺口分「核查未通过」「核查未完成」两组,时间线认得核查类日志代码;双盲复算写目录的预告和真写逐字一致(被目录挡下的那一边也说清原因,几个指标落到同一项时按组合预告);反方审稿说清「根本没反查」和「到底降不降档」;字段叫法挪到 labels.py;记录页的核查工件有名字和说明
2026-10-06 11:31:11 +08:00
ThearchyHelios
bef11d76ca
合入期 4 证据面板核查状态与打磨:证据接口带上双盲复算、反方审稿的状态,指标步骤里遮罩列的输入只写「已遮罩」;可验证报告里输入取自遮罩列的口径卡只给 id;推演与口径卡共用取整;运行对比离开后晚到的答复不再跳走
2026-10-06 11:31:02 +08:00
ThearchyHelios
6a9570f045
合入期 4 定时任务 × 运行对比:定时运行结束后自动和同一定时任务上一次成功的运行对比,结果存成工件记在触发记录上;触发历史和通知只给计数摘要与对比页链接,附封存哈希前 12 位;运行详情页头的定时任务来源改成键盘可达的链接
2026-10-06 11:30:56 +08:00
ThearchyHelios
ad745a930a
合入期 4 审批质询(后端):运行停在审批时针对报告里的一句话提问,只读 agent 现查现答,问答写进运行、随运行封存;遮罩按 SQL 认出改了名字的遮罩列再按值遮,SQL 只换在找某一个值的字面量;质询进行中批准、驳回、继续运行回 409
2026-10-06 11:30:56 +08:00
ThearchyHelios
a17c822d57
审批质询复核修正(第 3 轮,后端):SQL 里的字面量按语法树认用在哪,数字照原样留着的只有没夹住某一个值的范围边界和 LIMIT 行数;SQL 里留着的阈值只在回答正文里不遮,格子照旧按值遮;质询工件的免遮接线补上端到端核对
...
复核提出的问题和改法:
- 第 2 轮为了不误遮阈值,把范围边界、字符串的范围边界和选出列、函数参数里的数从正文和格子的按值遮里一并免掉;而按词认用法时,
简单 CASE 的 WHEN、IN (VALUES …)、行值、= ANY(ARRAY[…])、IS NOT DISTINCT FROM、套了括号的值这几种在找某一个值的写法被当成「别处」,
两头相同的范围(BETWEEN v AND v、>= v AND <= v)被当成阈值,遮罩值就留在封存的 SQL、回答正文和质询工件里,最后一道关也放行:
- 字面量改按语法树认用在哪:越过括号、负号、CAST、行值、VALUES、ARRAY、ANY / ALL 这些外壳再看上一层,上面几种都认作在找某一个值,
被比较的是哪一列也认得出(短的数照旧只在和遮罩列比较时换)
- 同一列上同一个值两边都被隔开的范围按在找这个值换:BETWEEN v AND v、>= v AND <= v、> v OR < v、整数的 >= v AND < v + 1,一头是几个数
算出来的(13900000002 - 1)也算;只从一边隔开的(>= v,或按 v 分成两段)照旧是阈值
- 数字照原样留着的只剩没夹住某一个值的范围边界和 LIMIT / OFFSET 的行数,而且同一个数在这条 SQL 别的字面量里没被换掉;选出列、函数参数、
算式里够长的遮罩值照第 1 轮换;字符串的范围边界照第 1 轮按值换。名字、注释里写着阈值不牵连阈值本身(AS 超过30000的笔数)
- SQL 里照原样留着的数只在回答正文里不遮,格子、列名、SQL 里照旧按值遮;同一个数在别的查询里被换掉了,正文里也遮。组装后的最后一道关
只放过正文里的这些数,渲染进单元格引用里的照旧拦下
- SQL 解析不了时认不准哪个数是阈值,一律不免,只按词认简单的等值比较
- 质询工件里两处免遮接线没有测试守住:报告指标、运行输入的值那一处,单笔目标那条端到端测试补上取质询工件,核对别的列里正好是这个数的
格子在回答、工件里都照常显示;SQL 里阈值那一处随上面的改法拿掉了(格子不再免阈值),补上「格子正好等于阈值」的端到端测试,核对回答和
工件里这一格一样遮住、两边对得上;阈值那条端到端测试补上取等值查询的质询工件,核对 SQL 和事件里一字不差
- 上面每种写法都补了单元测试和端到端测试(手机号存成整数、文字两种),另补开头带换行的 SQL 位置对得上、名字里的阈值不牵连阈值的测试。
查询清单的 SQL 现在要解析,改在线程里换(同 _plan)。每处改动都在副本上做过去掉实现、测试变红的验证
2026-10-06 11:02:10 +08:00
ThearchyHelios
a641bf5fb9
审批质询复核修正(第 2 轮,后端):和 * 写在一起、子查询里没起别名的遮罩列表达式认得出;SQL 只换在找某一个值的字面量,范围比较的边界、LIMIT 照原样;报告口径卡里的指标、SQL 里留着的阈值不当遮罩值;带前缀的字符串、名字、列名里的遮罩值也换
...
复核提出的问题和改法:
- 遮罩列的表达式和 SELECT * 写在同一支里、又没起别名(SELECT *, SUBSTR(buyer_phone, 4)),原值的一截出现在回答正文和质询工件里:
按位置认,* 前面的从头数、最后一个 * 后面的从结果末尾倒着数(结果的列一个不少、按顺序,重名也照留)。同一个根子的几种也一起补上:
子查询、WITH 里没起别名的表达式(外层的 * 原样带出来,列名各数据库起法不同)、两个 * 之间的项认不出落在哪一列,整份快照遮掉;
派生来源里 UNION 的另一支、带列名表的 UNION 按位置对上第一支或列名表的名字;LATERAL、多套几层括号照样认
- 和遮罩列做范围比较时的阈值、5 位以上的数不看上下文就被换成「已遮罩」,封存的 SQL 不是实际执行的那条:SQL 只换在找某一个值的
字面量(等值、不等、IN、LIKE、SQLite 的 IS)——和遮罩列比较的是遮罩值就换,和别的列比较的够长的遮罩值也换;范围比较的边界、
BETWEEN、LIMIT / OFFSET、选出列和算式里的数照原样(字符串的范围边界同样)
- 回答正文里复述 SQL 里照原样留着的阈值(「金额不低于 30000 元」)被遮:这些值本来就随 SQL 摆在读者眼前,正文、快照按值遮时免掉
(只免按值认的,SQL 里和遮罩列做等值比较的照旧换)
- 报告口径卡里的指标恰好是遮罩值时(单笔目标 20000),引用它的回答整份交不出去、换个问法也绕不过:报告列出的指标和运行输入的值
像问题里的数一样不当遮罩值,回答时和取质询工件时一样
- 带前缀的字符串(N''、E''、U&''、$$…$$)、带引号和不带引号的名字(AS "13900000001 的单"、张伟的单数)里的遮罩值原样封存:所有
字符串类的词只换引号里的内容,名字按值换;快照的列名、回答文档目录里的列名同样换,引用原列名的标记里的列名跟着换,正好对上
- 回答原文的标记里写着遮罩值时,单元格引用「Q1.r0.」后面的长号码会被当成小数的一截认不出来:标记按段换,单元格引用只换列名那一截;
遮罩值在组装之前就换掉,不再组装两遍,组装出来还认得出遮罩值的照旧不交出去
- 新加的接线没有测试守住:补上问题里写了遮罩列的短数时 SQL 原样保留、质询工件按报告快照里的遮罩值遮别的列,以及上面每一种情形
的单元测试和端到端测试。每处改动都做过去掉实现、测试变红的验证
2026-10-06 09:52:47 +08:00
ThearchyHelios
62b9361d88
期 4 复核修正(第 1 轮,后端):预告组合先算个数再列、上限按每项算,核查 agent 的两个日志代码归类,未能反查的句数守住不多于无法判断
...
- preview_joint 以前先把每一项的全部组合列成列表才和 JOINT_LIMIT 比,二十个指标落到同一项上就是几十亿种,在服务进程里(asyncio.to_thread)能把整个服务拖死;现在先按 ∏(1+k)−1−Σk 算出个数(超过上限即停),超了整项跳过、不列。上限也改成每一项各算各的:以前几项共用一份额度,前一项用掉以后,后面没超上限的项也被悄悄跳过,和文档说的「超过的那一项不预告」对不上。补两条测试:二十个指标落到同一项上时一个组合都不多列,两项各 72 种都预告
- review.py 认得核查 agent(双盲复算、反方审稿共用)发的两条:verify_unpriced 同 judge_unpriced 只是配置提醒,不再叫复核模型、给答案加降级说明;verify_limit 记成它自己的 kind(步数上限只有它说),不再落成笼统的 warn
- 反方审稿测试补上「未能反查的句数不多于无法判断」的断言(审批卡上的两个数靠这个约定对得上),模块说明改写准:触顶没给出结论的可能查过几次,原因里也有报告未引用数据库查询
- 双盲复算夹具加一种组合 time_rejected:业务日期被驳回过的那一列由退款率采纳(被挡下,带着写到哪),销售额采纳另一列;服务端先归拢、说法不同一项都不写(夹具测试按 record_choices 真写核对),审批卡没有合并预告时的推断按它检查
2026-10-06 09:31:00 +08:00
ThearchyHelios
5e6742b905
可验证报告里有输入取自遮罩列的口径卡只给 id,核对页把它当正常的无法核对
...
口径卡上记着每个输入的值和代入式:cell() 取的遮罩格、按位置取的 vars.res.rows[0][1],以前原样嵌进这份要发给别人的文件,
证据面板上已经遮住的号码在这里照样看得到。现在口径卡有一个输入取自遮罩列(遮没遮核对不了的也算),整张卡和带遮罩的快照一样
只给 id——没法只拿掉几个值,拿掉了哈希就对不上。认法和证据面板、推演同一个(recompute.input_origin):按定位里的列认,按位置
取的一格顺着取值链从写变量的节点在口径卡那次执行之前的产出起走;快照或产出读不出来、结果没存快照只带着数据源名的宁可多挡。
核对页(verifier.js)把带遮罩的口径卡当成正常的无法核对(「含遮罩列,未随文件附带,只能核对到哈希」),引用它的数字同样无法
核对;只有报告文档标着遮罩才判被改过。check-bundle 原来那项「口径卡标成遮罩判不通过」相应改成「报告文档标成遮罩判不通过」,
另加样本页 masked-card:口径卡在 ③ 无法核对、引用它的数字无法核对、总览通过、页面里找不到那个号码。去掉核对页的改动,这几项变红。
2026-10-06 09:20:29 +08:00
ThearchyHelios
be164bd5c1
证据接口复核整改(后端):反方审稿带整份报告的真实计数、跑停运行的审稿照样认得,双盲复算的跳过原因按指标说,遮罩核对不了的宁可多遮
...
反方审稿:unit.challenge 带上节点产出里整份报告的计数(counts)和没能反查的句数(unreviewed,产出里有才带)。证据面板借审批卡的
展示画这一句,以前凭这一句拼出「被推翻 1 句、其余 0 句」,读着像整份报告的结果。节点设为「报错并停止运行」、句子被推翻时节点报错、
没有 node.finished,以前证据接口认不出这次审稿;现在按审完那一刻的 challenge_done 日志认(只认审稿记录存上了的,处置写 fail),
运行因此失败了也看得到被推翻的是哪几句。
双盲复算:节点以 no_inputs 直通时,那句说的是整张卡。以前原样套到卡上每个指标,配了「复算的指标」子集时,明明取自查询、只是没被
选上的指标也写成「口径卡上没有来自查询的输入」。现在按这个指标自己说:不在子集里、值不是数的是 not_targeted,自己没有来自查询的
输入的才是 no_inputs,关闭了的照旧 disabled;节点跑了、没复算的指标同样这样分。
遮罩:认哪个输入取自哪份查询结果的哪几列抽成 recompute.input_origin,证据面板、推演(之后还有可验证报告)同一个认法。核对不了的
宁可多遮,和推演、可验证报告的原则一致:cell()、Agent 字段落在的快照读不出来;按位置取的一格(以 .rows[行][列] 结尾)取值链上的
产出读不出来;那份结果没存快照、只带着数据源名。证据面板不给值,mask_unverified 写原因、不进遮罩列;推演按读不出来处理,不给值、
不推演。既没带快照 id 也没带数据源名的结果(数据整形改过形状)认不出出处,照常显示,写进交付说明。
recompute.recompute 给双盲复算的预检和盲值用,整个指标重算不了时原因不再说「推演」(_Plan.stuck,判断同 blocked,只换措辞)。
按位置的遮罩接进 recompute 之后,双盲复算的预检对「cell() 输入 + 按位置取自遮罩列的一格」的指标判无法复算(以前照常盲算,遮着的
号码还会作为字面量进盲算模型的计算式),运行对比里这种输入两边都不给值:各补一个用例钉住。
一个指标里同一件工件只读一次:按位置取了好几格时,写变量的节点那份可能几 MB 的产出以前每格重读一遍。
补测:遮罩列上 Agent 字段、cell() 对不上时 model_value / snapshot_value 不在答复里;代入式重新代不出来时整条不给。
test_recompute 的夹具补上数据整形节点 parse 的产出:以前缺着,按位置取的那一格现在会因此核对不了。
去掉实现后新用例各自变红(计数、跑停的审稿、子集的跳过原因、两处宁可多遮、推演、预检措辞、按位置遮罩、只读一次)。
2026-10-06 09:20:09 +08:00
ThearchyHelios
7a6a8283aa
合入 SQL 差异说明收尾:判等价只用保持语义的规范化(去掉依赖表约束的改写),解析保真守卫拦下已知会被读错的写法(MySQL 反斜杠转义、特殊数字写法、比较 / 按位 / 前缀 NOT 没加括号地混用、PostgreSQL 符号运算符与 || 混用等),具体说法只在简单形状上说四类,其余给兜底并附逐行对照;回归语料与执行比对守住等价结论
2026-10-06 09:18:35 +08:00
ThearchyHelios
2eddd8236a
SQL 差异说明收尾:前缀的 NOT 后面同一段里既有谓词、又有算术 / 拼接 / 按位运算时(NOT status IN (…) * amount),SQLite 里 NOT 最松、sqlglot 读成 (NOT …) * amount,不在语法树上判等价、只给兜底;48 种组合两种方言都不再判等价,常见的 NOT … IN、NOT … = 照样认得出等价改写。模块说明照实列出仍做不到的几类说明准确度问题(Unix 秒的时间列、带 time 的时长列、被函数定死的列)
2026-10-06 09:18:10 +08:00
ThearchyHelios
778fb8b83e
审批质询复核修正(第 1 轮,后端):遮罩改按 SQL 认出改了名字的遮罩列、再按值遮,按值认有门槛、SQL 只换字面量;没写进记录的回答照样点得开;数据源核对是不是运行用过的那一个;报错和回答末尾的说明给提问人看得懂
...
复核提出的问题和改法:
- 遮罩列起了别名(本仓库查询的惯例是中文别名)、套了函数、经子查询或 CTE 转一道,原值会出现在回答正文、事件和质询工件里,第二遍组装也拦不住:按 SQL 认出改了名字的遮罩列(COUNT 只数个数、窗口的分区键只决定次序,不算;解析不了又写着遮罩列的,整份快照遮掉),快照另按值遮(别的列里写着遮罩值的格子);组装两遍之后正文里还认得出遮罩值的回答不交出去;提示词写明遮罩列不要选出原值、不要起别名
- 按值遮罩范围过宽:年龄这类短的遮罩值会把阈值、天数、日期、LIMIT 换成「已遮罩」,封存的查询清单不再是实际执行的 SQL。纯数字至少 5 位才按值认,日期、小数、时间、千分位里的一截不算;SQL 只换字面量和注释里的值,短的数只在直接和遮罩列(含别名)比较时才换;问题、选中原文里提问人自己写的值不换
- 提问人写的阈值在回答里被标「无出处」:问题、选中原文里的数作为 allow_numbers 交给两遍组装
- 同一条 SQL 事件里遮了、质询工件接口里没遮:工件接口直接用事件里记下的那条,遮罩值照回答时收(含报告自己的查询快照)
- 没写进运行记录的回答交回了工件 id,质询工件接口却一律 404:这样的回答在进程里留一小时(最多 200 条),这段时间里照样认它引用的工件
- 回答里引用的报告指标(m:)点不开:质询工件接口认回答文档目录里的口径卡
- 遮罩值上万个时每次回答、每次取工件都在事件循环里编一个上万分支的正则,卡住进程一秒上下:先按词、按开头几个字和长短筛出正文里真有的几个值再编;收值、解析 SQL、逐格比对放进线程
- 按名字认源:同名重建的源会被当成运行用过的去查,没固定版本的上传表格还会被悄悄补固定进已封存的运行。按运行里查询快照记的源 id、运行固定的版本核对,对不上的、没固定过的不交给 agent
- 封存之后的追问查的是现在的数据,读者分不清是口径差异还是数据更新:任务里给报告生成的时间,回答末尾注明
- 模型轮数用完被说成查询次数到顶,引用一个都解析不了照样算回答完成:轮数用完 limit 记 null;轮数用完、查询执行失败、引用解析不了都在回答末尾注明
- 报错透出核查 agent 的内部说法(「交结果」「按结构」、裸写的字段名):按情形换成发生了什么加下一步,原话只进日志
- 运行在执行时的说法对正式运行不成立、对过时的审批卡也没说清:带着审批卡来的叫人刷新,没带的按运行类别说什么时候能问
- 回答文档的工件引用 meta 记下问题的前 40 字,运行的工件列表据此认得出是哪个问题的回答
- 测试补上证明接线的用例:两道审批的竞态(approval_id 守卫)、上传表格按运行固定的版本查、设置里的上限和 data_versions 交到 agent 手里、开放途中运行被继续了、报告文档不属于这次运行;新增遮罩的单元测试。每条都做过去掉实现、测试变红的验证
2026-10-06 08:52:16 +08:00
ThearchyHelios
45fe01effe
定时任务自动对比复核整改(后端):只比成功的运行、按发起先后挑上一次成功的基准、和两边的封存绑定,对比挪到认领之前在锁外做并限时限并发;失败通知的处理行不再重复原因
...
- 只比成功结束的运行,基准也只取成功的:失败、取消的运行指标不全,和上一次比只会得出「移除 N 个」,拿失败的那次当
基准每个指标都成了「新增」。基准改成自己查同一定时任务、同一工作流、比这次先发起的运行里成功并封存的最近一次,
不再用对比接口的 default_base(按结束时间挑:老的失败运行事后被接着跑完,会拿后一次触发当它的「上一次」)。
中间隔着失败、取消的运行时,通知写「与上一次成功的运行(#短编号,日期)相比」,Fire.compare 多一个 previous
- 和封存绑定:运行的封存要盖住最后一条结束事件才算封存完(sealed_now)。runner 先写终态、再另起会话封存,失败后
接着跑完的运行在两步之间还带着失败时的清单哈希,以前这一拍会直接认领、按旧封存比、通知里写旧的清单哈希;现在
等新的封存,等不来就照常推送但不比、不写哈希。停在审批上的通知也不再写失败时留下的哈希。对比工件连同两边的清单
哈希一起存,触发历史发现任何一边不在终态或清单哈希变了就给 null;对比途中封存变了不记(条件写)
- 时机和时限:锁里只挑出状态有变化的触发,认领挪到对比之后、锁外按条件 UPDATE 做。对比最多等 20 秒(含排队),
同一时刻最多 2 个;超时只记警告,通知不带对比照常推送。停机时扫描在对比途中被取消,这次触发还没认领,下次照常
比、照常推(以前先认领、后比,这条通知会永远丢掉)。同一份封存已经比过的直接用记下的结果
- 失败通知:从没开始执行的,原因刚写过,处理行不再让人「查看原因」,任务在排期上写「下一次触发会照常发起」,停用
的写怎么重新发起;开始执行过的改成「请在 AgentLab 的「记录」中查看失败原因」,和挂起那句指向同一个导航入口
- 新增 test_scheduler_compare_guards.py(封存绑定、时限、取消、并发、复用),test_scheduler_compare.py 补真实缺
指标的失败运行、上一次失败、补跑老运行几种用例;去掉实现逐项验证过会变红
2026-10-06 08:48:56 +08:00
ThearchyHelios
b0cf23ddda
双盲复算审批卡的写目录预告和服务端逐字一致,盲算的理由按理由文档画(前端)
...
- 预告逐条说:会写的说「哪张表的哪一项会记为……」,不写的照服务端的原话说「不会记入:原因」(和裁决后时间线上跳过的原因一字不差),不再只有一句「不记」看不出为什么。三条分行列出,原因再长窄屏也不撑宽
- 被目录挡下的一边(已确认、驳回过、和已有条件合不起来)服务端照样带着写到哪,卡上据此认出几个指标是不是落到同一项上
- 同一次裁决里几个指标按当前的选择落到同一项上时,照完整对照里服务端算好的合并预告(catalog_joint)说:会写的是合起来的值、写明和哪几个指标一起记入,不写的照原因说;选择一变跟着换成那一组合的结果。工件里没有(老服务端、组合太多、工件还没取到)或认不出时,回到按其余指标当前的选择有条件地推
- 盲算的理由:对照工件带了 rationale_doc(核查 agent 组装、裸数字已标出)时按文档画,和反方审稿的理由同一种画法:有出处的数字画实线、挂盲算自己的查询编号,裸数字画点状线、挂「无证据」,下面再醒目地说一句;老工件只有正文,照旧纯文本
- 夹具 dual_check.json 补 catalog_blocked(目录里已有人工确认的业务日期时的真实预告)、merges 各组合的 catalog 与 joint(服务端按那一组合的目录算的真实输出)、filters_rejected(驳回过的条件),盲算理由换成 compose_doc 的真实输出;test_dual_check_fixture 核对预告与服务端一字不差、joint 里按选择取出的那一条就是真写的结果
- check-verify 补三节:被目录挡下的一边、照合并预告说并和真写核对、合并预告认不出时回退;理由文档的实线、裸数字、提醒和老工件的纯文本
- dual_check_facts._write 的返回标注改成和 _record 一致(写进去的说法或 None)
2026-10-06 08:11:02 +08:00
ThearchyHelios
095cc4c8ab
SQL 差异说明收尾(第 2 轮):PostgreSQL 符号运算符和 || 混用不判等价;条件写在聚合里、时间窗口、反连接、经主键定死的列不再说错
...
- 保真守卫(_misread):PostgreSQL 写成符号、sqlglot 却当成 LIKE 那一级来读的运算符(~、~*、~~、~~*、@@、-|-、@> 等)
和别的二元运算混用时拦下(PostgreSQL 里它们和 ||、& 同级、从左往右,status ~ 'p' || 'x' 是 (status ~ 'p') || 'x');
另拦 PostgreSQL 的前缀 @、|/、||/、COLLATE 后面的 ::;不知道是哪种库时拦块注释里套着的 /*、紧跟着字的 --、#、双引号
括起来的名字(MySQL 默认的 sql_mode 里是字符串)。都只给兜底,附原文的逐行对照。
- 条件写在聚合的参数里(SUM(status = 'paid')、COUNT(… OR NULL)、COUNT(NULLIF(…))、SUM(amount * (1 - is_deleted)))
算作这一边对这一列有条件(_Usage 的 case),另一边多出同一列上的 WHERE 条件时不再说「这一边没有这个条件」,只给兜底。
- 时间:timed 认 BETWEEN 和时间列上 LIKE 像日期的模式(paid_at LIKE '2026-09%'),时间窗口不再被说成有效行过滤;
「另一边没有按时间筛选」之前看另一边可能是时间窗口的条件(聚合参数里的时间比较、date_key、stat_month 这类列、
20260901 / 202609 这类整数、上下界一对),有就不说;认不准是不是时间列的窗口(_window_like)不说成有效行过滤。
两边的时间列在不同的表上时写成「表.列」。
- 反连接:用到 LEFT JOIN 可空一侧的列的条件(WHERE r.id IS NULL、r.order_id IS NULL)不说成有效行过滤,时间列在
可空一侧时也不说按它筛时间。
- 给了表结构时,聚合参数所在的表的键在组里定死了(按 u.id 分组时的 u.city),MAX 对 MIN、AVG(DISTINCT) 对 AVG 不说。
- 另一边原文也 LEFT JOIN 了、规范化因为结果不怕重复去掉了的表,不说「另一边没有关联」。
- 回归语料:收尾第 1 轮之后复验报的全部 blocker / major 收进 sql_pairs(_DIFF_R5、_DIFF_TIME_R5、_SAME_HARD_R5、
_SAME_SCHEMA_R5 执行;REGRESSIONS_R5、EXPLAIN_TRAPS_R5 只查结论),新增对应的测试。
- 模块说明照实补上:新增的守卫、时间条件的认法、只给兜底的情况、收窄换来的代价、MySQL 按默认 sql_mode 读的假设。
认出等价的比例:语料(SQLite,给表结构)169 对里 157 对,和改动前一样;PostgreSQL、MySQL 也不变;不知道是哪种库时
少认 1 对(same:quoted-names,双引号括起来的名字)。
2026-10-06 08:10:41 +08:00
ThearchyHelios
f8ac8dc1d6
定时任务自动对比收尾:基准那一次不在终态或被删时不给对比、对比工件读不出来时触发历史照常打开;检查脚本按实际底色量对比度
...
- 触发历史的 compare:以前只看这一次的运行在不在终态。基准那一次被强制删除、失败后被继续执行时,对比页比不了,
「对比上一次」链过去只会报错——基准一侧同样要在终态,否则给 null
- 对比工件读不出来(权限、磁盘出错)时记一条警告、给 null:以前 OSError 直接抛出,整页触发历史回 500。被改过
(内容与哈希不符)的以前就给 null,这次补上用例
- check-schedules:页头的定时任务链接、触发历史的「对比上一次」改成量 WCAG 对比度(≥ 4.5),底色顺着祖先叠到
不透明为止。以前比的是「字色不等于页头的底色」,页头本身透明,那样比永远成立;深色也补上同样的检查。另加一项
署名的立即运行配长名字:署名照写、链接截断、页头不横向溢出
2026-10-06 07:43:01 +08:00
ThearchyHelios
59f1868dac
可验证报告的运行结果按封存范围内真正截止的那条结束事件核对
...
早期运行先失败、经继续运行跑到成功的,封存范围里留着中途那条运行失败,成功结束的那条在范围外(run.finished 落库之前封存)。
以前 checkMeta 拿范围内最后一条结束类事件去对,把运行结果改成「已失败」也标「已核对」。现在只认范围内最后一条、且是结束类
事件的那一条;没有这样一条时,早期运行成功结束照旧说无法核对,别的说法写明那条失败之后运行又继续了、没有事件印证,判不通过,
页面顶上显示「—」而不是把文件里写的当成核对出来的。
样本页加一份 continued(先失败、继续运行到成功的早期运行),check-bundle 断言它原样时无法核对、运行结果改成已失败或已取消时不通过。
2026-10-05 19:06:32 +08:00
ThearchyHelios
4b52cccc75
证据接口带上核查状态,指标步骤不再露出遮罩列的值
...
核查状态:口径卡指标那一步多一个 dual_check(一致、不一致带审核人的选择和盲算值、无法复算带原因、跳过带原因),
读双盲复算节点封存的产出和台账条目,按台账里记的指标集工件认它复核的是口径卡的哪一次结果,直通的按画布上它复算的卡
和那一刻卡的最后一次结果认;句子多一个 challenge(判断、节点、审稿记录、实际生效的处置、报告名),只认审的就是正文
这一份报告文档的,记录没存上时按画布上审的报告和它那一刻的文档认、判断取产出里列的那几句。没有双盲复算、反方审稿的
运行没有这两个键,老运行的答复一字不差。
遮罩:以前只有查询步骤的结果窗口遮着,指标步骤的输入标签和代入式照样写着原值。现在 cell() 的格、Agent 字段按定位里的列认,
vars.res.rows[0][2] 这种按位置取自查询结果的标量顺着取值链认出是哪一列(recompute.positional_cell),遮的列和查询步骤
同一套;取自遮罩列的输入值写「已遮罩」并带上是哪几列,代入式里那几处同样写「已遮罩」,遮罩列进 redacted.columns。
推演用同一个认法,按位置取自遮罩列的输入同样不给值、不推演,证据面板和推演说的一致。
2026-10-05 19:02:52 +08:00
ThearchyHelios
a7333368f1
审批质询测试补全:封存之后的追问途中运行被继续了不写进记录、/verify 接口核对一致、批准和驳回都在回答期间被拦;接口说明写明质询工件的形状
...
- 失败的探索运行封存后追问,回答途中被继续运行:回答照样交回,recorded 为假,继续运行重新封存后核对一致
- 停在审批时质询、批准、封存之后,经 /api/runs/{id}/verify 核对,封存范围盖住这条质询
- 质询期间批准、驳回都回 409 inquiry_busy
- api/inquiry.py 的说明补上质询工件的返回形状 {id, content, masked[, mask_note]},以及回答文档原样给
2026-10-05 19:00:36 +08:00
ThearchyHelios
2db83a69e8
审批质询:只有空串算没指明句子、审批卡,0、false 这类照样报格式不对;结果相同的两次查询共用一份快照,引用列表里只记一次
2026-10-05 18:58:41 +08:00
ThearchyHelios
f62d6bf9d6
审批质询测试:署名照请求头记;写过的核查设置和花费账在测试结束时清掉,不留给同一进程里后面的测试文件
2026-10-05 18:57:57 +08:00
ThearchyHelios
9eeb11d29e
双盲复算写目录的预告和真写逐字一致:被目录挡下(已确认、驳回过、和已有条件合不起来)的那一边也带上写到哪张表哪一项、本来要写什么和原因;几个指标落到同一项上时,preview_joint 按真写的办法(归拢、拿掉驳回的、对目录)把每种选择组合算一遍放进对照工件的 catalog_joint,组合太多的那一项不预告;真写的日志 written 带上写进去的值。对照工件里盲算的输入另带 rationale_doc(核查 agent 组装的理由文档,裸数字已标出);补图级测试,按审批卡的认法断言预告与实际写入一致
2026-10-05 18:56:04 +08:00
ThearchyHelios
e6dfe18c83
审批质询自查修正:封存后的追问不一定来自审批人,提示词改成中性的「提问人」;告诉 agent 哪几列设了遮罩;组装回答出错照样记一条
...
- 任务里列出可查询的数据源现在设了遮罩的列,让 agent 不写出原值(系统的替换仍兜底)
- 回答原文没能组装成文档时不交出原文(引用没换成值、遮罩没做),记成失败,查过的和用量照记
- 第二次读状态时运行已被继续:不按旧封存追加,回 409
- 不指明句子、不在审批卡上问时,unit / approval_id 写空串等同于 null
- 只列有值的报告指标和运行输入:没有值的引用了也解析不了
2026-10-05 18:54:54 +08:00
ThearchyHelios
7df224106d
审批质询(后端):运行停在审批时,审批人针对报告里的一句话提问,只读 agent 现查现答,问答写进运行、随运行封存
...
- engine/inquiry.py:开放条件(停在审批且问的是待处理的那张卡;或已封存、核对一致的探索运行,追加在封存之后;
正式运行封存后、设置关闭、还在执行一律 409);同一运行同时只答一条(进程内登记);回答交给 run_verify_agent
(不传 emit,数据版本取运行记录,上限和模型按核查设置),任务里给被问的那句、照 judge.prepare 取的证据摘录
(遮罩照旧、原报告编号标明)、选中的原文和问题,数据源取这次运行用过的查询工具;回答由 compose_doc 组装成文档
落工件,数字可以引用自己的查询格子或报告已有的指标、运行输入,裸数字被标出;引用到遮罩列的格子渲染成「已遮罩」,
回答正文和查询清单里出现的遮罩列的值换成「已遮罩」;写入走 append_events,运行在回答期间变了就不写、照实说明,
触顶和失败照样记一条
- api/inquiry.py:POST 提问、GET 列表(按报告、句子筛选)、GET 质询工件(只认质询引用过的,遮罩照证据面板);
输入不合法回 {detail, field}
- api/runs.py:质询正在回答时,审批回复(批准 / 驳回)和继续运行回 409 inquiry_busy,拦在记签批人之前
2026-10-05 18:51:51 +08:00
ThearchyHelios
528b70af0d
推演重算与口径卡共用取整函数,补推演两处测试缺口
...
metrics.py 抽出 round_metric(只取整浮点、小数位须是整数),口径卡计算、代入式复算、推演重算和变化量都用它:
以前推演在 recompute.py 里另写一份取整,靠「真卡重算一致」的测试兜着,口径卡哪天换了取整方式,推演会对着同一张卡算出另一个数。现有的真卡重算一致测试保留。
补两处测试缺口:一个输入既嵌在下标里、又直接参与计算时,包着它的引用给了新值,排除行后它仍说不准(_doubt 里 moot 的那一支);
决定取哪一格的单格照给行段,勾掉它确定是排除后无法计算。两处都做过去掉实现、测试变红的验证。
2026-10-05 18:50:34 +08:00
ThearchyHelios
375f7165e5
反方审稿说清「根本没反查」和「到底降不降档」:产出和审批卡的概况加 unreviewed(模型不可用、触顶、数据源不在了等没能反查的句数,触顶但按查到的收了尾的不算)和 degrades(按降档处置、又接在带出具契约的成果节点上游时才为真,侧枝上、成果节点没带契约时为假);升级前的产出不带这两项,审批卡照旧规则说
2026-10-05 18:48:35 +08:00
ThearchyHelios
f0f1b99ead
定时运行结束后自动和同一定时任务的上一次对比:结果存成工件记在触发记录上,触发历史和通知只给计数摘要与对比页链接
...
- 新增 app/scheduler/auto_compare.py:通知扫描认领到运行进入终态(结束、失败、取消)的那一次之后、推送之前,
调运行对比接口的现成函数(default_base、compare_runs,不改它们)比一次。基准只取 default_base 的「同一定时
任务」那一档,退回「同一工作流」的不比——那不是这个任务的上一次。没封存的不比;比不了(基准封存核对不一致等)
记警告、意外异常记堆栈,都不影响通知。整份结果存成 run_compare 工件,不挂在运行名下(不进运行的工件列表),
工件 id 写进 ScheduleFire.compare_artifact;再次进入终态(失败后继续执行)时按新的封存重新比、覆盖旧结果
- 接口:Fire 多一个 compare: {base_run_id, summary}(summary 同对比接口的计数)或 null。运行现在不在终态
(被继续执行)、工件读不出来时为 null;工件摘要按 id 缓存(内容寻址,不会过期),读盘在线程里
- 通知:结束、失败的通知多一行「与上一次相比:只数据变 3 个、口径与数据都变 1 个、SQL 结构变 0 个」(三类总写,
其余各类有才写,两边都没有指标时不写一串 0 个),配了对外访问地址时附对比页链接(/runs/compare?target=…&base=…),
四种格式都带;通用格式多一个 compare 字段。只给个数,不放任何具体数字
- 没配 Webhook 的任务也比:触发历史里要用
2026-10-05 18:45:59 +08:00
ThearchyHelios
7083d5c457
修好数据版本测试的偶发失败:几条断言靠「第二版的 100 不在报错原文里」证明没改用当前版本,原文里却带着十六进制的随机源名,约五百个名字就有一个含「100」,断言无缘无故变红(和并行、时序、文件句柄无关);源名改成只有字母,另加一条守住这个约定
2026-10-05 18:45:59 +08:00
ThearchyHelios
64b6586ecc
出具缺口不再把节点类型说两遍:上游缺口的前缀在节点名就是类型叫法时只写一次(「反方审稿:」),双盲复算、反方审稿的缺口正文去掉自带的类型(「推翻了 1 句结论:…」「指标「X」两路结果不一致,审核人选择了盲算结果」);时间线和报错里那句照旧带主语
2026-10-05 18:45:59 +08:00
ThearchyHelios
67c7a42a3c
双盲复算、反方审稿的字段与取值叫法挪到 labels.py:field_label、option_label 按节点类型说「盲算模型」「结论被推翻时」「只标注」这些检查器上的叫法,发布门禁、升级预览不再说成通用的「模型」「启用」;schema.py 照旧再导出,校验和执行器的报错取同一份
2026-10-05 18:45:44 +08:00
ThearchyHelios
e62d6d2af4
时间线复核认得核查类日志代码:双盲复算、反方审稿的模型相同同裁判一样只记轨迹、不叫复核模型;触顶、两路不一致、无法复算、被推翻、没能反查、只查了部分数据源按各自的 kind 记成降级缺口,不再落成笼统的 warn
2026-10-05 18:45:25 +08:00
ThearchyHelios
d62f921ed4
定时任务遗留问题:失败通知不再许诺能继续运行、30 天前的触发停在审批上照样推送、调度循环测试不再依赖整分边界
...
- 失败通知的「处理」行改成中性的「请在 AgentLab 的运行记录中查看原因」:服务重启时还在排队、从没开始执行的运行
没有断点,「修正后可继续运行」是错的;开始执行过的也可能续不了(执行第一个节点前就失败、系统升级后断点不兼容),
能不能继续以记录页为准。没有开始时间的失败另写一行原因(没有可继续的进度),通用格式的 reason 字段同写;任务
还在排期上时补「下一次触发会照常发起」,和挂起(之后的触发都跳过)说清区别
- 通知扫描的 30 天窗口加两种例外:停在审批、有待审批的运行不受限制(创建 30 天以后才停到审批上的以前收不到
「等待审批」);运行记录 30 天内有过变化的照扫(等了一个多月的审批批完、跑完,以前收不到「运行结束」)。早就
结束、多日没有变化的旧触发仍不扫
- test_loop_ticks_until_stopped 改成只看「发起了」和停下前后的条数差:建任务和第一拍之间跨过整分时会先记一条
错过的跳过,以前按总条数断言偶发失败。加一组把下一次放在上一个整分的用例,必然走到跨整分这一支
2026-10-05 18:39:10 +08:00
ThearchyHelios
a122b98dd3
合入期 3 双盲复算与核查设置(前端):双盲审批卡(并排对照、差异说明、三选一与写目录预告)、检查器与节点卡片钩子、设置页「核查」一节、时间线解读双盲和反方审稿的日志
2026-10-05 18:08:39 +08:00
ThearchyHelios
e9cf74748f
合入期 3 反方审稿(后端):报告里的关键结论各派只读 agent 主动找反例,给出经受住、被削弱、被推翻、无法判断和有出处的理由;被推翻的计入出具缺口;审批卡附反方审稿概况
...
# Conflicts:
# backend/tests/test_issuance_upstream_gaps.py
2026-10-05 18:08:39 +08:00
ThearchyHelios
bee24cf79a
合入期 3 双盲复算(后端):口径卡上来自查询的输入另起看不到原 SQL 的只读 agent 独立复算,代回原式按误差比对;不一致时挂起交审核人三选一,选择只在差一个方面、且是排除无效记录这类数据事实时写进数据目录;发起时快照核查设置
2026-10-05 18:08:03 +08:00
ThearchyHelios
bcad199e0f
双盲复算前端复核修正(第 3 轮):同一次裁决里几个指标落到数据目录的同一项上时,卡上按其余指标当前的选择说——说法不同的改说都不记,有效记录条件说合成一句
...
问题:服务端写目录前把同一次裁决里落到同一张表同一项上的说法归拢(dual_check_facts._merged):业务日期、去重规则只要说法不同就一项都不写,有效记录条件用 AND 合成一句写。审批卡上的预告是每个指标单独算的,卡上不看别的指标选了什么:一个指标采用原流程(paid_at)、另一个采用盲算(created_at),两块里各自加粗说「记为……」,服务端一项都不写;两个指标都采用去重的一边、去重的列不同,也是这样。结尾只说按发起审批时的数据目录预告,看不出选择的组合也会让写入作废。审核人可能为了不让同一张表出现两个业务日期,把本该分开的选择改成一致。
审批卡(run/DualCheckApproval.tsx)
- 按其余指标当前的选择,给每个指标的两种选择各找出落到同一数据源、同一张表、同一项上的指标(peersOf)。只看预告会写的一边:选「两边都不对」、还没选的,服务端不会并进来。说法照服务端的 _same_fact 比:业务日期只看哪一列,其余压掉多余的空白比。
- 业务日期、去重规则说法不同时,那一句改说「……与「退款率」的选择说法不同,都不记」,不再算作会写。有效记录条件在「记为……」后面补一句「与「退款率」采用的条件用 AND 合成一句」。
- 选择一变,各块的说法跟着变。没选中的那几句也按别的指标当前的选择说,审核人改选之前就看得出这一选会不会让整项作废。
- 结尾改成「写入的项记为人工确认的事实;以上按发起审批时的数据目录和各指标当前的选择预告……」。原来是「两边都不对时不记。记为人工确认的事实」,读起来像在说不记的那一项。
- 没有预告时的结尾同样改。时间列、去重两句补上「同一次裁决里几个指标给同一张表记的业务日期(去重规则)不同时都不记」。
夹具与检查
- 夹具加 peers 和 merges。peers 换掉「退款率」对不上的那个输入,和「销售额」落到 orders 的业务日期、去重规则、有效记录条件上。merges 是四种组合:业务日期分开选、选同一列、去重的列不同、有效记录条件不同。
- peers 的差异说明和预告是服务端的真实输出。merges 的 written 是 record_choices 在空目录上真写一遍的结果。
- test_dual_check_fixture.py 新增两项。一项不依赖服务端,查每种组合真的落到同一项上。另一项在服务端合入后建临时数据源真写一遍,逐项比对。
- 在 vs/f1a 的 f7d1a2e 和 233afd1 上都跑过:8 项全过,regenerate 逐字节不变。
- 预览用例 dual-check-approval 认 peer 参数。
- check-verify 新增一节:
- 分开选时,两边加粗的那一句都说都不记,写明哪张表的哪一项、和哪个指标说法不同。
- 没选中的那一句按别的指标当前的选择说;一个指标改选两边都不对后,另一个回到「记为」。
- 选同一列照常记;去重的列不同都不记;有效记录条件说合成一句。
- 390px 下深浅色都不横向溢出。
- check-verify 没有预告的一节补两项:「人工确认」说的是写入的项;说法不同时都不记。
- 变红验证:去掉实现(peersOf 返回空),check-verify 变红 6 项;把有效记录条件也当成说法不同,变红 1 项;把还没选、两边都不对也当成采用了一边,变红 2 项。
- 改动后 297 项全部通过(原来 274 项)。check-all 里 check-verify 的耗时估计按实测改成 71 秒。
2026-10-05 17:47:21 +08:00
ThearchyHelios
6767b5f2fc
SQL 差异说明收尾(第 1 轮):不靠约束改写、解析保真守卫、具体说法只在简单形状上说四类
...
- 去掉所有依赖表约束的改写:凭主键 / 唯一键去掉 LEFT JOIN、去掉 DISTINCT,COUNT(列) 当 COUNT(*),凭 NOT NULL 去掉
IS NOT NULL(_unique_key_bound、_constraint_rewrites、_not_null_source 删掉)。SQLite 的类型亲和、COLLATE、部分唯一
索引、MySQL 的隐式转换都会让「唯一」不成立,宁可认不出;约束只拿来让说明少说(schema_cache 的外键也读进来)。
- 解析保真守卫(_misread,按方言切词、按括号深度分层):MySQL / MariaDB / 不知道方言时字符串里的反斜杠转义、1_000 和
0o17 这类数字、挨着写的字符串常量、同一层里没加括号地混用比较运算和 IS / IN / LIKE / BETWEEN / 另一个比较、按位运算
(含 COLLATE)和别的二元运算混用、XOR、不知道方言时的 ||、MySQL 以外的 &&:不在语法树上判等价,只给兜底,text_diff
给原文的逐行对照;normalize_sql 逐词规范化时数字和紧跟着的名字算一个字面量。
- 具体说法重写(_Explainer):只在两边都是简单形状(一段 SELECT、实表、普通连接,没有派生表、合并、窗口函数)时说,
只说四类——底层表上的时间列不同、一边多一个只涉及一张表的列和常量比的筛选条件(另一边对这些列没有任何条件、不是
被蕴含的、按取值逐段算过不是恒为真)、顶层聚合函数或去重不同、关联的表或关联类型不同(后面没有内连接引用可空一侧);
每句先确认真会影响结果(条件恒为假、结果看不见行、参数在组里定死、只取一行、表结构的键 / 外键说明不起作用时不说),
别的一律兜底。
- 回归语料:第 3 轮补充之后的复验报的全部 blocker / major 收进 sql_pairs(_DIFF_R4、_SAME_HARD_R4、_SAME_SCHEMA_R4
执行;REGRESSIONS_R4、DIALECT_SAME_R4、CONSTRAINT_TRAPS_R4 只查结论,约束陷阱另造小库执行),执行比对复验者列的 9 个
改松后拦不住的反例也收进来;旧的具体说法测试按新规矩改写。
- 模块说明照实写:等价怎么判、不靠约束、保真守卫、只给兜底的情况、已知做不到的。
认出等价的比例(给表结构):169 对里 163 → 157(96% → 93%),少的 6 对都是要靠约束才成立的;不给表结构 148 / 156 不变。
2026-10-05 17:35:51 +08:00
ThearchyHelios
233afd16ee
双盲复算复核整改(第 3 轮):驳回过的有效记录条件不再借着同一次裁决里的合并写回,合起来写时已有的段只写一次,补改名后分组的遮罩列用例
...
- 同一次裁决里几个指标落到有效记录条件上、要合成一句时,驳回检查原来只拿合起来的整句和驳回的说法比:「status <> 'refunded'」和「is_test = 0」AND 在一起就不再等于驳回的那句,被写成人工确认,和审批卡上「不写」的预告正相反。现在合并前按每个指标自己的说法过一遍驳回检查(_screen):带回驳回说法的指标拿出来不写,原因和它的预告是同一句话,其余的照写,备注只列真写进去的指标;合起来以后又包含了驳回的整句的也不写。有效记录条件的驳回检查改按段比,!= 和 <>、列名大小写、先后不同都认得出。
- 合起来的条件再和目录里已有的条件合写时,原来拿并好的整句去接,和已有条件部分重叠的整句原样接上,写出「status <> 'refunded' AND status <> 'refunded' AND is_test = 0」。现在接的是每个指标各自的条件,_and_join 只接还没出现过的段;已有条件是人工确认过的,原因里只说另外多出的那几段。最外层是 OR 的条件只在接了别的条件时加括号。
- Fact.also(其余几个指标)改成 members(并进来的每一个,各带自己的说法):并好的整句不再顶掉第一个指标自己的说法。
- 补用例:合并时驳回的条件拿出来、其余照写(facts 级和图级,真写和预告一字不差);驳回的整句由几个指标拼回来时不写;驳回时写法不同也认得出;合写不重复、已确认时只说多出的段;_and_join 的段级去重和括号;遮罩列改了名再分组(region AS area)时不收窄。
2026-10-05 17:23:17 +08:00
ThearchyHelios
b206665856
双盲复算前端复核修正(第 2 轮):「记入数据目录」不再说得比服务端宽——有服务端预告时照预告说,没有时只说必要条件、不写的几种照实说
...
问题:审批卡上那句「记入数据目录」的提示是照 vs/f1a 早先的规则写的。F1a 在 1491b5c 把写目录的规则收紧以后,有三种常见情况卡上说会记入,服务端却都不写:
- 只有一边按时间筛:卡上写「两边只差在按哪一列筛时间」,和正上方那条差异「盲算没有按时间筛选」自相矛盾
- 只多一个指标自己范围的条件(channel = 'web'):服务端只把排除退款、作废、测试这类无效记录的条件记成有效记录条件
- 只差去不去重,而审核人采用的是不去重的一边:服务端不写
审核人可能为了不让目录被写错,避开本来正确的原流程,结果出具降档;节点设为「判为失败」时运行还会终止。
审批卡(run/DualCheckApproval.tsx)
- 服务端在摘要里另带预告(payload.summary[].catalog,F1a 在 f7d1a2e 加的,约定之外另带)时照它说:三个选择各说一句,会写的写明哪张表的哪一项记成什么,不写的写「不记」。两边都不写就不提数据目录。审核人当前选中的那一句加重,选完一眼就能看出这一选会写什么。预告跟着摘要一起来,完整对照还没到或取不到时也照样能说。预告的形状认不出时整份不用,回到有条件的说法。
- 没有预告时(老服务端、升级前挂起的审批),三句改成只说必要条件(「仅当……才」),并把不写的几种照实写出来:只有一边按时间筛时不记;多出的条件得只在一边、并且是在排除无效记录,只看某个地区、某个渠道这类条件不记;采用不去重的一边时不记。
- payload 带了实际生效的「未采用原流程时」(同样是 f7d1a2e 加的)就照它说,不再去取图快照。子工作流里的节点在图快照里找不到,有了它也能说准;值认不出时仍回到图快照。
夹具与检查
- 夹具新增两个变体:只有一边按时间筛、只多一个渠道条件,差异说明都是 explain_sql_diff 的真实输出。每个指标、每个变体都附上服务端预告的真实输出(catalog_preview、variants[].catalog)。backend/tests/test_dual_check_fixture.py 有两项检查:一项不依赖服务端,查预告的形状和写目录的门槛;另一项在服务端模块合入后,逐项比对夹具和 dual_check_facts.preview。regenerate 也会一并重新生成预告。
- 预览用例 dual-check-approval 认地址参数 variant / catalog / on_reject,不带参数时 payload 只有约定里的几项。
- check-verify 按服务端的预告核对两种说法:没有预告的一节,在三种情况下都要以「仅当」开头,并照实说出不写;只差去不去重时,两种选择各断言一次。有预告的一节,核对两边写什么或不记、两边都不写时不提、选中那一句加重(去重的两种选择分别看)、认不出时回到有条件的说法、取不到完整对照时照样说,以及 390px 下深浅色的对比度。payload 的 on_reject 那一节核对:照它说、不取图快照、子工作流也说准、认不出时回到图快照。
- 去掉实现以后,检查脚本在这三种情况、预告和 on_reject 上共有 13 项变红。改动后为 274 项全部通过(原来 218 项)。check-all 里 check-verify 的耗时估计按实测改成 65 秒。
2026-10-05 16:56:05 +08:00
ThearchyHelios
0cd96fe327
合入运行对比加固:一个维度值占几行时按维度值数两边各引用了几行,部分行挤出引用的行段、单格换了同一维度的另一行都判说不清;维度列设了遮罩时照样核对、说明只写行号;补齐循环回边、写入者措辞、严格拆分范围、单边遮罩等守护用例
2026-10-05 16:44:22 +08:00
ThearchyHelios
f7d1a2ecba
双盲复算复核整改(第 2 轮):遮罩的分组列不收窄,收窄时去掉 HAVING,审批卡带上处置和写目录的预告,同一次裁决里的有效记录条件合起来写
...
节点(nodes/dual_check.py)
- 差异说明收窄到这一格时,分组键的结果列或它用到的列设了遮罩,就不收窄、照整条比。原流程、盲算各按自己那份快照
的遮罩(查询当时记下的加数据源现在设的)判断。以前按这一行的分组值补等值条件,「region = '华东'」这样的遮罩列
取值会跟着差异说明进审批 payload、human.requested 事件、对照工件和 dual_check_catalog 日志
- 按行收窄时连 HAVING 一起去掉:这一行既然在结果里,它所在的组就满足 HAVING。留着会多出一条「分组后的筛选」,
还会占掉「只差一个方面」的名额,真正的差异(比如时间列)就写不进目录
- 审批 payload 在约定的几项之外带上实际生效的 on_reject。摘要里每个指标另带 catalog:选 a、选 b 时,按发起审批
时的目录各会往数据目录里写什么({write: true, source, table, item, value}),不写的给出原因({write: false,
reason})。审核人要看得出不采用原流程会不会让运行失败、某个选择会不会被记成人工确认的目录项
(on_reject 以前只能从图快照里读,子工作流里的节点读不到)
写数据目录(dual_check_facts.py)
- 写入的判断拆成不读库的 _plan:真写(_write)和审批卡上的预告(preview)用同一套判断,不会说一套写一套
- 同一次裁决里落到同一项上的几个说法合成一项(_merged):
- 说法一样的只写一次,备注列出每个指标
- 有效记录条件用 AND 合成一句。derive 只收排除无效记录的条件,「排除退款」和「排除测试单」并不矛盾,以前两条
都被丢掉,原因还写成「互相矛盾」
- 业务日期、去重规则说法不同的仍然都不写,原因改为「给出了不同的说法」
- 合并后再和目录里已有的推断条件合起来写时,要求每个被采纳的一边都按已有条件筛过;有一个没按它筛,就不动并说明
是哪个指标
测试
- 遮罩分组列(原流程侧、盲算侧)的取值不出现在 payload、对照工件、节点产出和节点事件里
- HAVING 收窄后只剩时间列一处差异,并写进目录
- payload 的 on_reject、摘要里的预告(一致、已确认不覆盖、指标自己的范围几种情形)
- 有效记录条件合并(含和已有推断条件合写、有一个被采纳的一边没用已有条件时不动),同一说法只写一次
- 补上复核指出的三处接线缺口,各有一条图级用例:
- 带取舍的列名(gmv_by_order_date、paid_orders)不交给盲算
- 取值在运行输入里的排除条件不写目录
- 分组列上的 is_test = 0 不写目录
- 13 处变异(遮罩判断两侧、HAVING、上面三处接线、合并、预告、on_reject 等)去掉后,相关测试都会变红
2026-10-05 16:43:14 +08:00
ThearchyHelios
5f48f8727e
运行对比加固(收尾):区域等维度列设了遮罩时照样拿它核对两次引用的是不是同一批行,说明只写行号、不写值,挤出引用行段的和真的少了分得清,没挪的照常是数据变化;补单格反方向、归因维度按两边各自引用的行认、写入者改了配置时不严格拆分、并行支路查询四处守护用例
2026-10-05 16:41:59 +08:00
ThearchyHelios
52baa0d65c
双盲复算前端复核修正(第 1 轮):高亮按服务端真实的差异输出做,「记入数据目录」只在服务端真会写时有条件地说,后果和提示按节点的处置说
...
审批卡
- 对照两条 SQL:text_diff 是规范化之后的行(列名带表名、条件并成一行),和原文逐行对不上,原来按「两边逐行相等」高亮在真实输出上一处都标不出。改成两段原文按行做一次 LCS(不看空白、大小写和行尾逗号分号)高亮不同的行,一行都对不上时不乱标;text_diff 分原流程、盲算两栏,每行高亮(窄栏上下排)。
- 「只差一个方面、会记入数据目录」:照服务端 dual_check_facts 的门槛收紧——不等价、没用兜底、差异恰好一条(几个输入都对不上时合并后至少两条,所以也就是只有一个输入对不上),且是时间列、筛选条件或聚合;按这三种分别有条件地说会记成哪一项,选「两边都不对」不记、已有人工确认的不覆盖、以时间线为准。时间范围、两条筛选、关联、解析失败、多个输入合并都不再说。
- 后果和提交后的提示:payload 不带 on_reject,从这次运行的图快照里按节点 id 读「未采用原流程时」;判为失败时写明采用盲算或都不对会终止运行、提示也照实说,缺省时不再挂那句,读不到时有条件地说、提示不下结论。
- 只有解析失败时和摘要阶段一样按兜底说(固定那句 + 解析的原话),默认展开对照;兜底的原话另有原因(比较超时)时附在下面,一边没有 SQL 时不说「两条 SQL 的写法不同」。
- 认不出任何指标时留一个「驳回并终止」(approved 为假),运行不再一直挂着。
时间线
- dual_check_catalog 的 item 是目录项的键(business_date 等),按数据目录的叫法写成「「orders」(shop)的业务日期」,认不出的键不显示。
- dual_check_limit 的 metric 是指标 ID,不再当名字加引号。
- challenge_skipped 的 no_report 是报告文档读不出来(报告节点找不到时节点直接报错),说法和下一步改成去查报告节点有没有执行成功、在不在执行到的分支上。
检查器
- 字段名和服务端校验报错的叫法(schema.py 的 DUAL_CHECK_FIELD_LABEL)对齐,处置选项以服务端的短说法开头;check-verify 在服务端合入后逐项比对。
- 盲算模型移出高级选项:时间线「模型相同」的定位要找得到它。
- 上游有几张口径卡时写明必须选(服务端校验会挡住发起运行),不再说「建议指定」。
- 「跟随设置」的当前值每次打开检查器都重取,改了设置回到画布不再是旧值。
测试
- 夹具里的差异说明换成 explain_sql_diff 对同一对 SQL 的真实输出,新增几对 SQL 的变体;backend/tests/test_dual_check_fixture.py 核对夹具和真实输出一致,并可重新生成。
- check-verify 补真实形状下的高亮、各种差异下「记入数据目录」说不说、只有解析失败和兜底原因、按处置说后果和提示、认不出指标时的驳回、叫法比对、多张口径卡、设置重取;check-decode 改用服务端真实的日志形状。check-verify 的耗时估计按实测改成 45 秒。
2026-10-05 16:10:55 +08:00
ThearchyHelios
1491b5c7f3
双盲复算复核整改:指标自己的筛选范围不再写成有效记录条件,盲算不再看到原流程的列名,差异说明收窄到这一格
...
写数据目录(dual_check_facts.py)
- 有效记录条件只收「排除无效记录」的条件:被排除的取值是退款、作废、测试这类(或码值表里写着这类意思),
标记列只认留下有效记录的一边(is_test = 0、is_valid = 1、deleted_at IS NULL);取值出现在指标名称、口径说明、
所在分组、运行输入里的,用到分组列的,一律不写,原因写明「可能是指标自己的筛选范围」。以前「华东销售额」的
region = '华东' 会被记成订单表人工确认过的有效记录条件,之后所有查订单表的工作流(含下一次盲算)都只看华东
- 目录里已有的有效记录条件被采纳的一边也按它筛了的,和新条件合起来写(已确认的不改,照实说);没按它筛的不动。
以前整项替换,两边都用着的 is_test = 0 会被静默丢掉。推断的去重规则说法不同的也不替换
- 业务日期只在两边都按时间筛、按的列不同时才写;一边根本没按时间筛的不写
- 采纳了不去重的一边不写去重规则:那是指标自己的算法,写成「不去重」会把别的指标带偏
- 同一次裁决里几个指标对同一项给出矛盾的说法,整组都不写
节点(nodes/dual_check.py)
- 盲算任务里不再给原流程结果的列名和同一行的维度列名:分组的只给取值(日期说成「2026-09-02 这一天」),
原 SQL 写死的文字列连取值也不给;只有几项输入都来自查询又没写口径说明、列名看不出取舍时才给列名。
以前「order_date 为 2026-09-02」等于告诉盲算按下单日归属,下单日和支付日的陷阱正好漏掉
- 差异说明先把两条 SQL 收窄到这一格(只留算出这一列的那一项,分组的按这一行的分组值改成等值条件)再比,
多列查询、分组取一行时不再混进「选出的列」「分组」这类噪声,只差一个方面的也写得进目录
- 产出状态:全部一致才是 agreed,一个都没核成是 unchecked,核成一部分是 partial;产出和台账加 counts;
无法复算的指标发 dual_check_unchecked {metrics: [{id, name, reason}]}
- 共用一格的几个指标触顶时每个指标各发一条 dual_check_limit
- 查询次数刚好用完、交回的格子是真查出来的照常比对(时长、金额触顶仍按无法复算)
- 审核人没选或选了认不出的照实记「审核人没有对指标作出选择」,不再替人记成「两边都不对」
- 盲算先单独做第一个,其余最多 3 个同时进行,避免串行撞上运行单段的时长上限
配置
- 画布校验:双盲复算配了失败重试报错(重试会把盲算整轮重做、再问审核人一次);enabled 用 is 判断,0、1 不再放过
- 发起时的核查设置快照:子工作流(按运行时的取法读)里有双盲复算、反方审稿节点时也快照
- 助手节点说明补一句不要给双盲复算配 retries
测试:补上遮罩两道防线、规范化后一致但值不同、两个输入都对不上、只复算配置的指标、原值为 0、摘要最多 3 条、
驳回、多列查询、分组取一行、指标筛选范围不写目录等用例;每条核心改动都做过去掉实现、测试变红的验证
2026-10-05 15:54:03 +08:00
ThearchyHelios
eea098e975
运行对比加固(第 3 轮):单格要是同一个区域的同一行;归因按哪组维度说就按哪组维度核对;快照里行和列对不上的说不清;补单格反方向、行段只差最后一行、精确性一侧等变红测试
...
- 单格(数组字段的一个元素)引用的那一行两次是同一个区域,还要是它同样的那一行:按查询结果的先后,排在这一行前面的、它的行数两边一样。区域 × 日期的结果东区少了一天,第 3 行从南区的第一天变成第二天,原来报成只数据变、南区少了 5(同一天的南区其实多了 10,正负号反了),同一处引用换成一行的行段却说不清;按金额排的第 2 行从东区第二高的那天变成最高的那天、取第二个元素的也一样。只比排在前面的行数,不比外面还有没有它的行:东区两天还是一天、第 1 行都是东区第一天的照常是数据变化
- 行段核对引用的是不是同一批维度值时,按两边整份结果认出的维度核对一遍,再按归因用的维度(引用的那段行上认出的)核对一遍,两组都切在同一处才算同一处。渠道在引用的行里两边都只有「线上」、归因按区域说:南区第二天走了线下、挤到第 5 行,原来只按(区域, 渠道)核对,报成只数据变、南区 -100%,和「南区真的只有一天」一字不差,反方向也是;区域 × 渠道取前 2 行、南区新开的线下排第 3,归因 300 → 280,快照里南区是 300 → 480。只按归因用的那组也不够(只引用一行的认不出维度;引用的行两边都只有东区、只有整份结果分得出区域的也要核对)。取行的规则抽成 _attributed_rows,归因和核对共用
- 快照里有的行和列对不上、认不出各行是哪个维度值:原来退回按行号认、报成只数据变,现在和快照读不出来一样说不清,说清是哪一边
- 新测试:单格同一区域换了一行(两个方向、按金额排、取第二个元素、排在前面 2 行对 1 行、只有一行的行段同样说不清、同一行的对照);按归因用的维度核对(渠道挤出、反方向、新开线下,各带对照,占比之和为 1;只引用一行时仍按整份结果的维度核对);行和列对不上(两个方向);单格反方向(这次取的区域在基准运行里,只是不在这一行);行段只差最后一行;精确性一侧(第 4 名每周不同、后面剩的行数不同,仍是数据变化);排在前面的行数 2 对 1、位置说明里的行数、两边都只引用一部分但行数不同、基准一行都没引用时说哪一边;引用的行两边都只有东区时按整份结果认区域;金额列存成文本时也不当维度;只在一次运行的图里有的下游节点;不归因时整体说明照样提遮罩
- test_an_element_only_needs_the_same_region_on_its_row 改名 test_an_element_does_not_mind_other_rows_of_its_region:单格不再只看区域,原名和说明都不对了
2026-10-05 15:52:51 +08:00
ThearchyHelios
4d364d385b
反方审稿复核修正(第 2 轮):照录的理由不露内部标记、裸数字注明无出处,只停用了部分数据源时理由和时间线写明没查哪几个,撞上每日金额上限的几句同一种说法
...
- 不采信时照录反方的理由改成纯文字:解析不了的引用(⟦?v:…⟧)换成「(引用无效)」,裸数字后面注明「(无出处)」。
这种句子没有理由文档,界面按文字显示,以前内部的占位标记会原样露在审批卡上,裸数字也不标
- 一句该查的数据源只停用了一部分时照常反查,理由末尾由系统注明哪几个没查(写进理由文档:界面按文档画理由,
写法和把说明写进原文再组装出来的一模一样),时间线另记一条 challenge_sources_lost。以前只写进给 agent 的任务,
审稿记录和审批卡上的「经受住」看着就像每个源都查过了。没挂依据的句子按整份报告用到的源查,任务、理由里不再说
「这句引用的」
- 当天的核查金额用完时,派出去就撞上上限、一次模型都没调用的那句,和后面不再派出的句子用同一种说法
「已达上限(…),这句未反查」,不再一句「反查未完成:…没能交结果」、一句「这句未反查」
- 判失败的报错只推翻一句时说「请核对这句结论」
没有改的:被推翻的出具缺口读成「反方审稿「反方审稿」:反方审稿推翻了…」并归在「校验不完整」下,审批卡和节点产出
分不出根本没反查,challenge_unreviewed / challenge_sources_lost 不在期 3 约定的日志代码表里——这几处要改约定或
别的包的文件(io.py、decode.ts、NodeCard.tsx、EvidencePane.tsx、ChallengeSummary),留给编排者定
2026-10-05 15:50:20 +08:00
ThearchyHelios
c38177aea6
SQL 差异说明第 3 轮补充:只在一边被去掉、被按内连接比的 LEFT JOIN 不说成「另一边没有」「用 INNER JOIN」
...
规范化在一边认出了「这次 LEFT JOIN 有没有都一样」(去重之后不怕重复、按主键关联、只取可空一侧跳过空值的聚合),另一边
写法不同没认出来时,两边的规范形式一个有关联、一个没有(或者一个内连接、一个 LEFT JOIN),以前会照规范形式说「A 没有
关联 refunds 表」「A 用 INNER JOIN」,可原文两边都写着 LEFT JOIN。现在去掉的关联记在那一段上(_DROPPED_JOINS)、按内
连接比的记在那张表上(_NULL_BLIND),差异说明碰到就不说;表结构里有唯一键、又没用到的那张表,ON 写得认不出是不是按
唯一键关联(s.id IN (o.store_id))时也不说。补了三种写法在三种方言、给不给表结构下的测试。
2026-10-05 15:09:10 +08:00
ThearchyHelios
4ceac6b74c
反方审稿复核修正:没有出处的结论不采信,推荐接法下审批卡有报告,重试和接着跑不重审、不拿旧审稿冒充
...
- 出处:一条查询都没执行成功的判什么都记为无法判断,判「被推翻」的理由里还得引用到自己的查询结果——零查询的推翻能让
正式出具降档,零查询的「经受住」会给审批人假安心。系统写明原因,反方原本的结论和理由照录。这句引用的数据源都已
停用时不派 agent;核查模型本身用不了时后面的句子照同一个原因记,不再逐句去建模型
- 时间线:有句子没能反查时另记一条 challenge_unreviewed(带第一条原因),challenge_done 的说法分开写查过的和没查成的
- 审批卡:「报告 → 反方审稿 → 人工审批」时审批说明不引用正文也认得出这份报告(reviewed_report_ids 穿过直接连着的
反方审稿,reviewed_by_human 同步),审稿概况附得上
- 重试与接着跑:同一次执行里的重试沿用已经审完的结果,不再多花一份钱、也不会把「被推翻」重审掉;审稿结果带输入指纹
(报告、文档、反方模型、上限、遮罩),接着跑时只改「结论被推翻时」沿用,改了审稿本身就重审
- 处置:产出和审批卡里的 on_refuted 写实际生效的 degrade / flag;「报错并停止运行」配「出错时:记录错误并继续」画布
校验挡住,跳过校验的旧图执行时改按出具降档;反方审稿不在带出具契约的成果节点上游时画布给警告(降档不会发生)
- 摘录里指向原报告查询的写法(指标取自查询 Qn、查询 Qn 的 SQL、出现在查询 Qn)都标成「原报告 Qn」,和反查 agent
自己的 Q1 分开
- 选项叫法和检查器下拉一致:出具降档 / 只标注 / 报错并停止运行,「启用」写跟随设置;助手手册同步
- 补测试:快照里的反方模型和每日上限、裁判判成不是结论的句子不审、审批卡只给被审的那份报告挂概况
2026-10-05 15:08:53 +08:00
ThearchyHelios
87f0979a90
SQL 差异说明第 3 轮补充:NOT 按德摩根律往里推;结果看行出来先后的一段不拆 BETWEEN、不去 MIN / MAX 里的 DISTINCT
...
- NOT (p AND q) 写成 NOT p OR NOT q、NOT (p OR q) 写成 NOT p AND NOT q(p、q 是条件时,三值逻辑下照样成立),在
外连接改写、唯一键判断之前也做一遍。复验者的「意思一样却说了具体的不同」压测脚本在本轮的按主键去掉 LEFT JOIN
上找到了:ON 写成 NOT (NOT (s.id = o.store_id) OR NOT (s.region = 'east')) 时认不出按主键关联,说成「B 用 LEFT
JOIN 关联 stores 表,A 没有」;往里推之后两边一样。
- 结果看行出来先后的一段不拆 BETWEEN、不去掉 MIN / MAX 里的 DISTINCT、不按德摩根律改写(一个 BETWEEN 和两个比较
估算出的行数可能不同,换一种扫描的先后,GROUP_CONCAT 拼出来的先后就跟着变)。
- 测试:德摩根律的等价改写进 _SAME_R3,NOT (a AND b) 对 NOT a AND NOT b 进 _DIFF_R3;「排除」那条说法跟着往里推
之后的写法改。
2026-10-05 15:06:48 +08:00
ThearchyHelios
44e4597037
运行对比加固(第 2 轮):行段要把引用过的每个区域切在同一处——一边整个被引用、另一边只引用了一部分的,引用的行数没变少也说不清;只在一边有的区域那一边算整个被引用;引用的行不从第 1 行开始时还要是它同样的那几行;单格只看那一行是不是同一个区域
...
- 一个区域在一边整个被引用、另一边只引用了一部分(其余的行还在快照里):上一轮只在「有行在外面的那一边引用得少」时判说不清,南区这次多了一天、引用的行只盖住前两天(行数没变少,甚至更多)照样报成只数据变,归因和「真的只有这几天」的对照一字不差,反方向连正负号都反了;现在按切法比:两边都整个被引用,或者都只引用了它同样的那几行,才是同一组数
- 只在一边的快照里有的区域,没有它的那一边算整个被引用:北区这次新出现、三天只引用了两天,基准运行南区只引用了一天、这次南区没了,都说不清;新出现、没有了的区域整个被引用的照常是数据变化
- 引用的行不从第 1 行开始时,按「排在引用的行前面的行数、引用的行数」认引用的是它的哪几行:两边都只引用了东区一行,基准是它金额第二高的那天、这次是最高的那天,说不清,说明里写出两边排在前面的行数
- 单格(数组元素)只看引用的那一行两次是不是同一个区域,不套行段的切法:东区两天还是一天,第 1 行都是东区的第一天;第 1 行的东区真的没有了照常比
- 说明说引用的行外面有它的那一边,两边都有的说引用得少的那一边;几个区域切法都不同时说基准运行引用的行里先出现的那个
- 截断的快照仍按取回的行比(和引用整份结果一致,挤到截断点后面的行看不到,不做归因),写进文档
- 新测试:一边整个一边部分(这次多一天、这次引用得更多、反方向,各带真的只有这几天的对照,占比之和为 1)、切在同一处(两边都只引用南区第一天仍是数据变化)、行数不同两个方向的说明、几个区域都不同时说哪一个、排在前面的行数不同、只在一边有的区域(新出现、没有了)、两列维度一起认(含一边只有一个值的区域列)、单格只看那一行、挤出两行时的行号和行数(两个方向)、正好 3 行不写「等」、两个 Agent 都交得不同时点名画布上靠前的、单边遮罩时整体说明提到遮罩
2026-10-05 14:47:05 +08:00