ThearchyHelios
2cf329648d
上传表格的日期列按导入时配方里的逻辑类型认:双盲复算选了时间列不同的一边时,上传源也能写业务日期
...
J1 给业务日期加了类型门槛(两边的时间列都在表结构里声明为日期 / 时间类型才写),而上传表格导入时日期一律按文字保存、表结构里总是 TEXT,上传源因此永远写不了业务日期。导入时配方里其实记着每一列的逻辑类型(导入确认时界面上标的「日期」):列表块里类型为 DATE 的列、交叉表的日期轴。查过别处:构建回执里只有存储类型(列表的 DATE 列和文字列一样记 TEXT、role 都是 text),简单导入的回执只有 INTEGER / REAL / TEXT,所以只按配方认。
- dual_check_facts.recipe_dates:一份配方里逻辑类型是日期的列({表: [列]}),表和列按 recipe_types.derive_tables 推,和建表同一份;日期轴写进它各分段的表,列表合计行另存的表不带日期列;类型按 _DATED_TYPE 认,只有时刻的不算
- dual_check_facts.upload_dates:只读,按数据源当前快照找配方(source_versions.snapshot_recipe_id,期 3 之前的快照取最后一期导入的),和 schema_cache 出自同一个版本;手工源、简单导入、快照或配方记录不在、配方解析不了一律给空
- 节点的 _source_info 带上 upload_dates,放进候选:审批卡的预告(preview / preview_joint)和裁决后的真写认的是发起审批时读的同一份,逐字一致;旧的 checkpoint 里没有这一项,照旧不写
- _dated_problem:上传源里按文字保存的列在 upload_dates 里的算日期列(按表结构认出的表名、列名去对,大小写不论);不在的、读不出配方的照现在的原因说「来自上传的表格,表格里的日期一律按文字保存」;声明成别的类型的、只有时刻的照旧
测试:derive 一级补导入认作日期的写、只有一边是日期 / 读不出配方 / 记在别的表上的照旧说按文字保存、手工源不认 upload_dates、按表结构的名字对、preview_joint 同样认;新文件 test_dual_check_upload 经真实导入接口建上传源(暂存 → 改配方 → 试运行 → 提交、简单导入),配方里两列都是日期的审核人选盲算后业务日期记「支付日期」(人工确认、备注写运行),支付日期是文字的选哪边都不写、预告和跳过原因一字不差,配方记录改坏了的照旧不写;去掉认日期、去掉候选里的 upload_dates、去掉日期轴各做过一次,测试变红。
2026-10-06 16:54:30 +08:00
ThearchyHelios
3f17fd3c71
合入期 5 前置修复 K4:运行把这一段执行的截止时刻交给节点(engine/deadline.py),反方审稿与双盲复算开始每一项前看剩余时间,按剩余时间收紧每项时长、给下游留出余量,来不及的记为未能反查 / 无法复算并写明「运行时限将至」,整次运行不再被时长上限中止;继续运行取 checkpoint 里的结果不重复反查
2026-10-06 16:26:45 +08:00
ThearchyHelios
4314a7fc44
合入期 5 前置修复 K2:核查与裁判模型的输出额度提到 16384,服务方嫌大时退回 4096(和助手共用 providers/budget.py);每次调用认截断,因推理占满额度没交出结果时照实说(verify_truncated、judge_truncated),不再说成盲算没查到、没按结构交结果
2026-10-06 16:26:37 +08:00
ThearchyHelios
54ab06d615
合入期 5 前置修复 K5:写作模型把整篇报告包在 markdown 代码块里时去掉外层围栏(重写的几轮同样处理),结论句照常可审、裁判和反方审稿有句子可看;别的语言的代码块、围栏外有文字、多个代码块、开闭不配对的原样不动
2026-10-06 16:26:37 +08:00
ThearchyHelios
39068c9636
合入期 4 整合 J2:审批质询遮罩收口——阈值只在同一个数在别处确实被换掉时才遮、夹住某一个值的边界按条件与作用域认、质询工件里未遮罩文字格夹着的遮罩值按值换掉;算式边界、分档标签列、CAST 类型参数等变体照实处理,已知局限写进模块说明
2026-10-06 16:23:26 +08:00
ThearchyHelios
76b485a0ca
审批质询遮罩收口(第 3 轮复核):标签列按作用域认取自哪个来源,UNION 另一支、子查询里的遮罩列流进标签列照收;取模、整除、整数相除按算出来的值认;CAST 的类型参数不当边界换
...
复核留下的一条 major(第 2 轮只修了一部分)和两条次要问题:
- 分档标签列:以前按名字认,从「所有名字都只装着标签」起往下剔。遮罩列原样选出(SELECT vip_level)时名字就是它自己,
永远剔不掉;结果的 UNION 按位置那一遍只往里加标签,另一支取的是遮罩列也不剔;派生来源里的 UNION 根本不按位置看。
于是标签在前、遮罩列在后(不起别名、别名不同、外层再套子查询、CTE 里的标签再 UNION),遮罩列经按原名选出的子查询、
以标签的别名传出,或者两个子查询 JOIN 起来同名,等级 1 撞上 THEN 1 都不收,WHERE vip_level = 1 在查询清单、事件、
质询工件里照原样封存(对基线是回退)。现在 _label_columns 按作用域认每一项取自哪个来源:结果的这一列在 UNION 的
每一支里都要是结果全为写死常量的 CASE / IIF,或者取自子查询、CTE、LATERAL 里只装着标签的一列(派生来源里的 UNION
也按位置看每一支,写了列名表的按列名表);取自数据源里的表的一律不算,哪怕和标签同名。没写表名的列,派生来源出
这一列的就是它(SQL 执行过,别的来源就没有同名的列,不然报列名有歧义),按这一列 USING、NATURAL 合成的除外;递归的
CTE、UNION 里落在某一支 * 里的列认不准,照收(多遮)
- 取模、整除:_arithmetic、_worked_out 补上 %、MOD、DIV、//(往零取整,同 SQL)。顺带 / 照数据源的算法算:SQLite、
Postgres 里两个写成整数的数相除只留整数部分(sqlglot 记在 typed 上),以前一律按小数算,age >= 25 AND age < 53 / 2
在 SQLite 里夹住了 25 却认不出;写成小数的(53.0 / 2)、MySQL、DuckDB 照小数算
- CAST 的类型参数(第 2 轮引入,只多遮):_halves 只收往上走得到这一边的字面量(_lifts),CAST(30000 AS DECIMAL(10, 2))
的 10、2 不再当成算出边界的数换掉,SQL 检查结果的片段里别处的 10、2 也不跟着换;_wraps 里 CAST 只算被转换的那个值,
Oracle 的 CAST … DEFAULT 0 ON CONVERSION ERROR 里的 0 照原样
- 模块说明的已知局限照实更新:标签列认得出、认不准的几种写法;认得出的算式补上取模、整除和整数相除,认不出的补上
位运算、POWER、CAST 改了值的
测试:单元补标签在前、遮罩列在后的八种写法(不起别名、别名不同、子查询里的 UNION、写了列名表的 CTE、CTE 里的标签再
UNION、经按原名选出的子查询传出、两个子查询 JOIN 同名、RIGHT JOIN USING 同名列),按作用域仍认得出的五种标签(外层连上
数据源里的表不写表名、按别的列 USING、两层子查询写了表名、UNION 两支、派生来源的 UNION 经 * 带出);取模、整除、整数
相除的六种写法和照小数算的三种;CAST 的类型参数和 DEFAULT。端到端补 UNION 标签在前的两种写法、取模和整数相除算出来的
边界。每处实现都逐个去掉验证过测试变红(十一个变异全红)
2026-10-06 16:01:28 +08:00
ThearchyHelios
5d4d1fdc15
审批质询遮罩收口(第 2 轮复核):算式边界、套了 CAST / 汇总的列、换个写法的数、两头不是整数、范围再排除一头都认得出;只装着标签的列才不收标签;截断片段整段去掉
...
复核留下的三条 major 和两条次要问题:
- 范围的一头是算式(age <= 25 + 0、buyer_phone BETWEEN 13900000000 + 1 AND 13900000009 - 8):夹住的值认得出,算式里的数
却照原样留着,一算就是那个号码。现在几个写死的数的加减乘除按算出来的那一个值认(_lifts):夹住某一个值的边界、等值、
IN 里的算式,里面的数都换;选出列里算出来的号码按值换;没夹住的算式阈值和写成一个数的阈值一样照原样,正文里复述它
(连同算出来的值)不遮,算出来的值在别处换掉了也不留。原有两条用例(BETWEEN 13900000001 AND 13900000002 - 1、
… AND 13900000001 + 0)的期望随之改成算式里的数都换(多换一个 1、0,号码照样不露)
- 几种找值写法以前认不出:被比较的一边套了 CAST、汇总(CAST(age AS INTEGER) = 25、HAVING MAX(age) BETWEEN 25 AND 25)
改按它的值取自哪些列认(_columns_of);同一个数换个写法(25.0、025、2.5e1、013900000001)按规范写法和遮罩值比
(_canonical);两头不是整数的范围(age > 24.5 AND age < 25.5、BETWEEN 25 AND 25.9)在整数上隔开紧挨着的两个整数;
范围再用不等、NOT IN 去掉一头(buyer_phone >= 13900000001 AND buyer_phone <= 13900000002 AND buyer_phone <> 13900000002,
以前号码被当成阈值、回答正文跟着不遮):等值一类只在同一个条件里和范围合起来看,整数上紧挨着的被排除的数越过去接着
看(age <= 30 时 27 照样成立,不算夹住),跨条件配对仍只看范围比较,不等、IN 单拿出来不当「写出了这个值」
- 算式求值改成不递归(_constants):visits <= 1+1+…写到 1500 项时以前超过递归深度,整条 SQL 退回按词认,同一句里夹住的
年龄照原样封存
- 分档标签不收进遮罩值的规则太宽(第 1 轮引入):改了名字的遮罩列(vip_level AS 等级)的 1、2、3 撞上同一条 SQL 里按
条件数个数的 THEN 1 ELSE 0,1 就不算遮罩值,WHERE vip_level = 1 照原样封存。现在只跳过只装着标签的列的格子
(_label_columns:选出项本身是结果全为常量的 CASE / IIF,或者经别名、子查询、CTE 原样传下去的,没起别名的按位置认;
同一个名字在哪一处装着别的就照收)
- SQL 检查结果的说明:码值表里的码值和别的字一样按值换,说明照实写(多遮,不漏),补测试钉住
- 截断的片段停在带空格的遮罩文字值中间(地址):以前只去掉最后一段,前半截还留着;现在从没闭合的引号、注释起整个去掉
- 模块说明的已知局限照实更新:两个产品取舍保持;夹住的认法补上不等、NOT IN、两头不是整数和越过排除数的规则;新增一条
列出认得出的找值写法和仍认不出的(值藏进和列一起算的算式、拼接、函数拼出来的值)
测试:单元补算式边界、套了 CAST / 汇总、换个写法、两头不是整数、排除一头、不该夹住的几种(范围加不等仍不只一个值、
IN 列表旁的阈值、选出列里的等值和 WHERE 的范围)、上千项连加、改了名字的遮罩列撞上标签、标签列经子查询 / CTE / 没起
别名、截断片段、码值表;端到端补长号码的五种写法(算出来的边界、算出来的等值、两头不是整数、范围再排除一头、补零)、
年龄的六种写法和改了名字的等级列。每处实现都逐个去掉验证过测试变红
2026-10-06 15:08:56 +08:00
ThearchyHelios
48f656f362
证据裁判截断的回复整批不采信,截断另记 judge_truncated,时间线的下一步指到换模型
...
复核第 1 轮的发现:
- 有的网关把截断的强制工具调用解析成半截清单:第一条判定写完、第二条只写了编号。_ask 拿到清单就交出去,不再看截断,于是记成一句支持、一句格式不对、两句未给出判定,llm.end 也不标截断。现在回复被截断就整批记 truncated(最后一条可能只写了一半,也可能判定写完、理由写到一半,分不清哪条完整),纯文本调用同理
- 截断的那一批原来只发 llm.end(时间线标题「结论句裁判未能执行」)和 judge_failed(下一步「检查裁判模型的接入后重新运行」):截断时接入是好的,同一个模型重新运行多半还是截断。现在另发 judge_truncated(max_tokens、unjudged),judge_failed 不再带截断;时间线上调用那一行说「裁判模型的输出达到上限(N token)被截断」,judge_truncated 那一行的下一步指到在报告撰写节点的「结论句裁判」或设置里换不带推理的裁判模型,入口落到节点的结论句裁判;check-decode 加一节
- 复核层(review.py)认得 judge_truncated:是缺口,记成它自己的 kind
- 退回小额度按 budget_refused 认,和核查同一种记法记在进程里:之后每份报告、每次点击直接用小的
测试补上半截清单(剧本和真实 ChatAnthropic)、纯文本清单后面还在写、截断和格式不对各记各的日志、跨报告记住被嫌大、自建服务的 max_new_tokens
2026-10-06 14:30:15 +08:00
ThearchyHelios
4905de728c
核查截断的回复一律不采信,触顶原因的先后照旧,截断的建议按模型从哪来的说
...
复核第 1 轮的发现(主要一条):Anthropic 的工具调用写到一半到了上限时,回复照样带着 tool_use(input 是空的,有的网关给半截对象)。工具循环只在没有工具调用时才看截断,于是一轮轮执行空参数的查询,撞到步数上限,最后记成「没有按结构交结果」;收尾的强制工具调用截在半路时解析出空对象或半截对象,空对象记成没按结构交,反方审稿的半截对象(结论写完、理由写到一半)被当成「经受住」,质询把半句话当成回答。
- 工具循环:回复被截断就停,带着的工具调用不执行(半截的 SQL 查出来的数是错的),也不收尾
- 截断前查到过东西的也不再按查到的收尾:截断前查到的不一定是要的那个数,交出去的结果只在 notes 里写一句「可能不完整」,审批卡、反方结论、质询回答都看不到,残缺的结果还照常参与比对和处置。同时长到点一样算半路被掐断,原因照截断说,查过的照记;TRUNCATED_SETTLED 和日志里的 delivered 字段去掉
- 收尾:回复被截断时,解析出来的、从回复里抠出来的都不采信(结构化、普通调用都是),也不退回普通调用
- 上一轮的 give_up 把触顶原因的先后从「先 stopped」换成了「先 refused」:去掉 give_up,收尾被上限拦下时照旧报先撞上的那个(双盲复算按它写无法复算的原因,反方审稿按每日上限决定还派不派后面的句子)
- 截断的原因开头只说「未能给出结果」(质询里提问人看到的就是这句,不说「核查未能完成」);建议在节点里说「在节点上指定不带推理的模型,或在设置里更换核查模型」(节点上的模型优先于设置,和时间线上的下一步一致),质询只说设置
- 退回小额度按 budget_refused 认,按 (接入, 模型, 额度) 记在进程里
- 时间线:verify_truncated 的副标题固定说「这次核查未能给出结果」,check-decode 跟上;review.py 里 verify_truncated 的注释跟上
测试补上真实 ChatAnthropic(只有 HTTP 层是假的)的循环截断、收尾截断(空对象、半截对象),真实 ChatOpenAI 写到一半的工具调用参数,Bearer 鉴权下 SDK 在本地拒绝时退回 4096,自建服务的 max_new_tokens,跨次核查记住被嫌大,触顶原因的先后
2026-10-06 14:30:03 +08:00
ThearchyHelios
e3f5d566d0
核查因运行时长上限将至没核成的,时间线另起一条并带上原因(cause: run_deadline);收紧过的核查 agent 触顶时也改说时长上限将至;给下游留的余量看下游还有几个要调模型的节点,时长上限调短时余量跟着缩小
...
为什么(复核第 1 轮):没开始的句子、指标和收紧后到点的,以前和别的原因记在同一条日志里,没有可机读的字段,界面只能照旧叫人调高每句、每项的上限(调高了只会更快撞线),或去查核查模型和数据源(它们本来就没问题);前面有一句因别的原因没审时,运行时长上限这个原因还被藏进「等」里。双盲复算只给下游留 60 秒,惯常接法「双盲复算 → 写报告 → 反方审稿 → 成果」里写报告一慢,运行照样在写报告时被中止;时长上限调到 180 秒左右时,固定的 60 秒余量又让核查一项都开始不了。
- 反方审稿:没开始的句子另发一条 challenge_unreviewed,带 cause、run_seconds,不混进别的原因;收紧后到点的那条 challenge_limit 照记 timeout_s(老界面认得),另带 cause、run_seconds 和触顶的句数 claims,同一节点里有句子触了自己的上限时两条分得开。产出的 unreviewed 照算
- 双盲复算:没开始、收紧后到点的盲算结果带 cause、run_seconds,_compare 记无法复算时一并带上(只这一行),dual_check_unchecked 按有无 cause 分两条发,时限将至的那条另带 cause、run_seconds,原话列指标名(最多 5 个)
- deadline.relabel 包住交给核查 agent 的 emit:收紧过的那一项到点时,verify_limit 改说「本次运行即将达到 600 秒的时长上限,时长已按剩余时间收紧到 52.3 秒」,带 cause;别的事件、别的上限原样转发,没收紧时原样交回
- 余量按份算:一份取 60 秒和这一段的 10% 中大的,这一段不到 240 秒时按 25%;下游这一段里(到人工审批为止)每个还要调模型的节点(模型、Agent、协作、子工作流、写报告、双盲复算、反方审稿)各再加一份,合计不超过这一段的一半。默认 600 秒的一段、下游只有成果节点时和以前一样
- 没有截止时刻时一切照旧;决定都还在原来的 @task 里,接着运行取 checkpoint
测试:反方审稿、双盲复算各补一条「另一个原因 + 时限将至」两条分开说、带不带 cause 的用例,反方审稿补一条触了自己上限和收紧后到点分得开的用例;原有用例补上 cause、run_seconds、原话的断言。假的钟钉住下游有写报告时第 3 项只查 40~50 秒(没有时 100~110 秒);真的钟用 10 秒一段、盲算查到时长用完、写报告要 3 秒,以前在写报告时被中止,现在运行成功。单元测试钉住短时长的余量、下游每个节点加一份和一半的上限、数下游节点(人工审批之后不算、汇合只算一次、环回自己不算)、relabel 改什么不改什么。去掉下游余量、去掉 relabel 后对应用例都变红。
2026-10-06 14:25:38 +08:00
ThearchyHelios
dde0927460
审批质询遮罩收口(第 1 轮复核):「夹住某一个值」在整条 SQL 里认,只有分档的几种写法各算各的;分档标签不当遮罩值;SQL 检查结果的片段、说明照整条 SQL 换
...
- 夹住:上一轮只在同一个条件里配对,把找值拆到 ON 和 WHERE、WHERE 和 HAVING、INTERSECT / EXCEPT 两支、包在 CASE / 函数 / 算式里、子查询和 CTE 里,完整手机号就照原样封存、回答正文也跟着不遮。现在整条 SQL 里配对,只有 CASE 的不同分支、IIF 的真假两支、SELECT 里不筛行的不同项(选出列、GROUP BY、ORDER BY)、UNION 的不同支各算各的(_apart,看最近公共祖先);同一个条件里照旧按合起来的真假细看。整数上 <= v、>= v 也隔开相邻的整数(age <= 24 OR age >= 26 就是 age <> 25);BETWEEN v AND v、>= v AND <= v、> v OR < v 条件里哪一层这样写都算(被更宽的范围吸收、旁边有矛盾的条件、隔着别的条件写也认得出),整数的半开区间仍只看整个条件,成百个相邻分档照旧不遮。条件的各层摊开一次反复用,600 档的耗时和上一轮相当
- 分档标签:CASE / IIF 结果全是写死常量的,标签文字是 agent 写在 SQL 里的,不收进遮罩值,规格原句的 SQL、回答里的档名照原样;当分组键(每一档一行)或套在汇总里按条件数个数(SUM(CASE … THEN 1 ELSE 0 END))不算派生值,格子照常显示,分得清哪一档几笔;逐行的标签列、汇总遮罩列本身的值照旧整列遮
- 质询工件的 SQL 检查结果:片段是检查器重新写出的表达式,单拿出来认不出在找哪一个值,改为按整条 SQL 里整个换掉的字面量换(简单 CASE、行值、BETWEEN v AND v 里的短的数也换掉,阈值照原样);说明里照引的取值(「没有码值「3」」)一样换;截断处半截的号码去掉
- 同一个短的数在别处换掉时,别的列上的阈值、LIMIT 照原样:一律换会回退第 2 轮起的「age = 25 AND amount > 25 … LIMIT 25」,写进已知局限并补测试钉住
- 模块说明的已知局限照实改写(分档拆进两个 CTE / FROM 子查询、同一选出列里两档汇总相除会多遮,拆进 CASE 分支 / 不同选出列认不出,运行详情的工件页签不经这里的遮罩)
- 测试:端到端改回规格原句(文字档位、SUM(CASE …)、年龄段 CASE),补 ON/WHERE、WHERE/HAVING、INTERSECT、包在 CASE 里、CTE、相邻整数的端到端用例,单元补拆分写法、被吸收的 BETWEEN v AND v、分组标签、检查结果片段与说明;每处去掉实现都验证过变红
2026-10-06 14:05:52 +08:00
ThearchyHelios
a7b8854dc4
双盲复算复核修正(第 1 轮):业务日期只认带日期的类型、原因按哪一边说清;遮罩列在子查询或 WITH 里改了名不再收窄,交给盲算的分组取值按 SQL 认出取自遮罩列的;按位置取的格点名原因、认不出出处的不写进计算式、不再改变容器输入的判法
...
业务日期的类型门槛:只有时刻的 TIME / TIMETZ 不再算(一天里的几点几分不是日期,MySQL 还常拿它存时长;和 catalog.is_date_column 同一个口径,记成业务日期后 SQL 检查会对按真实日期列统计的查询一直报错误级),原因说「只有时刻,不含日期」。类型照表结构里记的说「类型是 X」(introspect 存的是 SQLAlchemy 反射出来的类型,SQLite 里写成 TIMESTAMPTZ 的反射成 NUMERIC),没写类型的列反射成「NULL」,按没有声明类型说。被采纳的一边有问题说「被采纳的盲算按时间筛的列……」,未被采纳的一边另说清为什么也要看它(两边都是日期列时,审核人选的才是业务日期按哪一列)。数据源还没有可用的表结构(未探查、探查失败)时说表结构不可用,不说这一列不在表结构里。上传表格建的数据源(origin=upload,节点认出后经候选的 uploaded 交给 derive)日期一律存成文字,原因说「来自上传的表格,表格里的日期一律按文字保存」,不说成用户声明了 TEXT;预告和真写逐字一致。
遮罩:收窄补等值条件、交给盲算的分组取值,都按 SQL 认出取值来自遮罩列的名字(复用审批质询的 inquiry._derived_hidden:起别名、套函数、经子查询或 WITH 转一道、写在列名表里的都认,解析不了又写着遮罩列的整份算)。以前外层按 area 分组、area 在子查询里由 region 改名而来时照常补上「area = '华东'」,差异说明还原成「region = '华东'」进了审批卡、对照工件和目录日志,「华东」也进了盲算的任务;和遮罩列无关的 WITH 照常收窄。按位置取自遮罩列的输入直接交回「输入 vars.res.rows[0][0] 取自设置了遮罩的列,不能用于复算」(同 cell() 的说法),「核对不了」改成「无法核对」。伸进查询结果的行、却认不出取自哪一列的(下标不是字面量、改过形状的结果没带快照 id 和数据源名)计算式里写成「其他输入」,不把卡上的值交给盲算。按位置取的格落在的快照只为认遮罩算遮罩,不再进重算的快照清单:以前同一个指标里装着它整份行的容器输入会对上它、被它的遮罩列挡下。
2026-10-06 13:42:51 +08:00
ThearchyHelios
9f0e453884
整篇包在 ``markdown 里、中间再套一段一样长的 ``sql 时照样去掉外层围栏:带信息串的一行开、不带的一行收,两两配对。以前一样长的内层围栏一律不去,模型最常见的这种写法仍是 0 句结论,裁判和反方审稿没有句子可审,正式运行照样出具
...
规则:中间和外层同种符号的围栏行,比外层短的跳过,比外层长的不去(规格原文),一样长的按配对看——带信息串的开一个代码块,不带的收掉它;没有可收的 ``` 说明外层在这里就收了(好几个代码块),开着时又来一个 ```sql、扫到最后还开着的,都不去。去掉外层后 compose_doc 和前端每见到一行 ``` 开合一次,配好的一对正好切成一个代码块,原 docstring「见到 ``` 就收」的理由不成立,改准确了。
一样长的行只认 compose_doc 和前端认得的写法(信息串是紧跟着的一个词):``` sql 这种它们不认,算一行正文。不然它会和后面的 ``` 配成一对、去掉外层,而后面那个 ``` 在它们眼里成了开头,把结论句吞进代码块。比外层长的照旧按行首判,````sql title 这样的也不去。
外层反引号里套 ~~~、四个以上反引号的代码块照常去掉外层:compose_doc 和前端只认 ``` 围栏,这段按正文核对,和模型不包外层、直接这么写时一样,比整篇一个代码块强;docstring 写明,测试钉住。
测试:same-fence-inside 挪到去的一边,补多段内层代码块、~~~ 里套 ~~~、反引号里套 ~~~;不去的补没有可收的 ```、开着时又来 ```python、内层没收、``` sql 开头、更长的带词围栏。compose_doc 一级补 ```markdown 套 ```sql(SQL 仍是代码块,结论句 2 句)和 ~~~ 块按正文核对。端到端(正式运行,裁判 + 反方审稿 + 出具契约)加一组套 ```sql 的写法:两句都判、都审,完整出具。裁判退回改写(rewrite_once)那一稿也包在代码块里时照样去掉:改写稿被采用,第二轮判到改过的那句,以前这条路没有测试守着。每条判断各做过一次去掉、测试变红。
2026-10-06 13:32:38 +08:00
ThearchyHelios
3bb06e32f1
整理:核查收尾时一条报错的续行对齐,裁判的 _TRUNCATED 挪到用它的 _ask 前面
2026-10-06 13:13:49 +08:00
ThearchyHelios
d9acfbfc0b
收紧后的时长取到 0.1 秒、往下取:核查 agent 触顶时时间线写「时长上限 69.7 秒」,不写 69.7012 这样一串小数;往下取不会超出算好的余量,差一点不够的照样不开始
...
另把 segment、allot 的说明补全:deadline 为 None 时放的是 None(里面看不到外面的截止时刻),配置的是不限时按收尾宽限算最短时长。
2026-10-06 13:07:23 +08:00
ThearchyHelios
2c2672cc04
时间线认得核查模型的输出被截断(verify_truncated):标题说「核查模型的输出达到上限(N token)被截断」,副标题说这次核查未能完成或已按截断前查到的结果收尾,下一步指到换不带推理的模型,入口落到节点的模型
...
decode.ts 按结构化字段(max_tokens、delivered)解读,不从原话里认,缺字段时只给不带数的标题;文案放在 terms.ts 新的 VERIFY_TRUNCATED_TEXT。check-decode 加一节:先核对 verify_agent.py 还是这么发的,再核对三种取值(没交出结果、退回 4096 后交了结果、缺字段)的标题、副标题、下一步、入口和原话。
跑完之后的复核层(engine/review.py 的 WARN_CODES)登记 verify_truncated:同 verify_limit 记成它自己的 kind、degraded,不落成笼统的 warn,也不触发「重跑一次大概率能好」。
2026-10-06 13:06:18 +08:00
ThearchyHelios
4a3de10d38
证据裁判按 16384 的额度判、服务方嫌大时退回 4096,判定写到一半到了上限的记未裁判(truncated),照实说是输出额度
...
裁判原来固定 4096、thinking off;经 OpenAI 兼容接入的推理模型收不到 thinking=off,思考能把 4096 用光,结构化调用写不出判定、退回纯文本也一样,最后记成「裁判返回的结果格式有误」。现在:
- 额度 MAX_TOKENS(16384),服务方嫌大(400/422 且报错提到 max_tokens 一类)时退回 FALLBACK_MAX_TOKENS(4096)再问一次,之后各批都用小的、只撞一次;小额度的模型要退回时才建
- 每次调用看有没有被截断:Anthropic 的 stop_reason=max_tokens、OpenAI 系的 finish_reason=length、openai 结构化输出抛的 LengthFinishReasonError。截断的这一批记未裁判,原因是新的 truncated(和格式不对分开记:说成「格式有误」人会去查提示词,该换的是模型),理由写「裁判模型的输出达到上限(N token)被截断,这句未裁判。通常是推理占满了输出额度,可换用不带推理的裁判模型」,缺口、llm.end 的 error(带 truncated、max_tokens)、judge_failed 日志同样写明
- 结构化调用被截断的不再退回纯文本多花一次额度;截断那次的用量从异常里取,照记账
- 别的批照常问(同格式不对);没有截断时原有说法不变
测试:新增 test_judge_truncation(结构化调用截断、LengthFinishReasonError、纯文本只有思考、一批截断不影响别的批、退回 4096 只撞一次、退回后截断写 4096、格式不对的说法不变)。
2026-10-06 13:02:24 +08:00
ThearchyHelios
b54545b5d4
双盲复算在运行时长上限内收尾:每项盲算开始之前看这一段执行还剩多少时间,不够就不再开始、按无法复算记缺口,够的话时长上限按剩余时间收紧;运行不被中止
...
为什么:盲算最多 3 路并行、每项 120 秒再加 30 秒收尾宽限,指标多了一样能耗光一段执行的时长上限,整段盲算没进 checkpoint,「继续运行」全部重做、再花一次钱。
- 只动安排盲算的 _blind:开始一项之前问 deadline.allot。不够时交回一个没有模型的结果(原因「本次运行即将达到 600 秒的时长上限,为保证运行按时完成,未进行盲算」),走现有的路径:_compare 记无法复算、dual_check_unchecked 点名、出具缺口照记;第一项就不够时和核查模型用不了一样,后面的不再一个个去试
- 时长收紧过的盲算到了点:照样按无法复算记(同触了每项时长上限),原因说运行时长上限将至、盲算时长已按剩余时间收紧;不留 limit,不发 dual_check_limit——它叫人调高每项的上限,调高了只会更快撞线
- 决定都在 dual_check_blind 这个 @task 里:审批恢复后重放取 checkpoint 里的结果,不再盲算,哪几项没来得及照旧
- 时间充裕时时长上限照传原值,和以前一样;_plan_metric 等别处没动
测试:假的钟钉住五个指标只够盲算 2 项、第一项都来不及、收紧的那项到点怎么说、审批恢复后不重做;真的钟用 5 秒的时长上限、一项接一项的慢盲算,以前被中止,现在运行成功。去掉判断后这几条都变红。
2026-10-06 13:01:20 +08:00
ThearchyHelios
4a3899f4d5
反方审稿在运行时长上限内收尾:每句派出去之前看这一段执行还剩多少时间,不够再审一句就停下,这句和后面的记为未能反查,节点照常收尾、运行不被中止;够的话这句的时长上限按剩余时间收紧
...
为什么:逐句串行反查(为了时间线看得出哪条查询在审哪一句、每日余额扣得确定,这个设计保留)默认 5 句、每句 90 秒再加 30 秒收尾宽限,最坏正好是一段执行的 600 秒,加上取数、写报告必然被中止;中止时反查的 @task 没做完,「继续运行」从头再审、再次超时。
- 判断用 deadline.allot(给下游留余量、扣收尾宽限),只在要派 agent 的句子上做:没有可查数据源这类不花时间的句子照记原来的原因。一旦停下,后面的句子照同一个原因记(同每日金额用完、核查模型用不了的处理),理由写「本次运行即将达到 600 秒的时长上限,为保证运行按时完成,这句未反查」,challenge_unreviewed 的原因写「……剩下 N 句未审」,产出的 unreviewed 照算进去
- 时长收紧过的句子到点按查到的结果收尾,challenge_limit 照记 timeout_s(界面认得),说法另起:说运行时长上限将至、反查时长已按剩余时间收紧,不说「每句时长上限 90 秒」——那会叫人调大每句的上限,调大了只会更快撞线
- 决定都在原有的 @task 里做,输入指纹不含截止时刻:接着运行时取 checkpoint 里的审稿,不重审,没来得及的照旧
- 时间充裕时时长上限照传原值,和以前逐字一样(现有用例全过)
测试:假的钟(每派出一句拨钟若干秒)钉住 5 句只够审 2 句、收紧的那句触顶怎么说、一句都来不及、接着运行不重审;真的钟用 7 秒的时长上限和查不完的慢 agent,以前被中止,现在运行成功、计数对得上。去掉判断后这几条都变红。
2026-10-06 13:00:48 +08:00
ThearchyHelios
a1d5dcd0ac
runner 把这一段执行的截止时刻交给节点:进入 asyncio.timeout(max_run_seconds) 时放进 ContextVar(engine/deadline.py),退出时清掉,节点、节点里的 @task、子工作流都看得到;没有上限时为 None,节点照旧
...
为什么:反方审稿逐句串行反查、双盲复算按项盲算,一个核查节点就能把一段执行的 600 秒用光,整次运行被中止,装着反查、盲算的 @task 没进 checkpoint,「继续运行」从头再来一遍、再次超时。核查节点要先知道还剩多少时间,才能在上限之内收尾。
deadline.allot(时长上限, grace=收尾宽限) 给核查节点在开始每一项之前问:先给下游留出余量(60 秒或这一段总时长的 10%,取大的:60 秒够成果节点复核、再做一两次普通的模型调用;时长上限调大了的,节点多半本来就慢,余量跟着放大),再扣掉收尾宽限,剩下的比配置的时长短就收紧到它;收紧之后不到 min(配置的时长, 收尾宽限)(一次模型调用的时间)就不再开始。不经 runner 执行时原样放行、时长上限还是传进来的那个值。
runner 只改一行:async with deadline, segment(deadline.when(), max_run_seconds),截止时刻就是 asyncio.timeout 的那一个、同一个钟。测试钉住 allot 的各档、余量随总时长放大、退出(含出错)时清掉,以及节点和节点里的 @task 都看到同一个截止时刻、审批恢复后的那一段重新计时。
2026-10-06 12:59:49 +08:00
ThearchyHelios
a552f4feab
核查模型的输出额度改为 16384、服务方嫌大时退回 4096,截断照实说:工具循环、收尾的每次调用都看有没有到了上限被截断
...
额度:judge.MAX_TOKENS 从 4096 改为 16384(核查的 verify_model_spec 沿用它)。经 OpenAI 兼容接入的推理模型收不到 thinking=off,思考算在额度里,4096 常常想完就没额度发查询、交结果;16384 是常见网关接受的输出上限里偏大的一档,cite_fields 的抽取也是这个数。服务方嫌大(400/422 且报错提到 max_tokens 一类)时退回 judge.FALLBACK_MAX_TOKENS(4096)再试一次,工具循环和收尾共用一个开关,之后都用小的;小额度的模型要退回时才建。
截断:工具循环里没有工具调用、finish_reason=length(或 stop_reason=max_tokens)不再当成「模型说完了」,一条查询都没成功时不再收尾(收尾只能交「查不到」,双盲复算就会记成「盲算没有查到这个数」);查到过东西的照常收尾,取不到要的数时同样交回截断的原因,取得到的照常交、notes 里注明。收尾被截断(Anthropic 强制工具调用写到一半、openai 结构化输出抛 LengthFinishReasonError、普通调用只有思考)时交回截断的原因,不再退回普通调用多花一次额度;截断那次的用量从异常里取,照记账。给人看的原因写明「核查模型的输出达到上限(N token)被截断,核查未能完成。通常是推理占满了输出额度,可在「设置 → 偏好设置 → 核查」中换用不带推理的模型」,经 error 交给双盲复算的无法复算原因、反方审稿的「反查未完成」、质询的报错;节点里调用时另记一条 verify_truncated,llm.end 标出 truncated 和额度。没有截断时原有说法不变。
测试:新增 test_verify_truncation(假模型返回 finish_reason=length、只有思考、LengthFinishReasonError,覆盖工具循环、收尾结构化和普通调用、退回 4096、别的 400 不重试、三条渠道);三处钉着 4096 的断言改成 16384。
2026-10-06 12:58:37 +08:00
ThearchyHelios
0600144b73
写作模型把整篇报告包在一个代码块里时去掉外层围栏再核对:不去的话整篇在 compose_doc 里是一个代码块,裸数字照样标出,可一句结论都切不出来,证据裁判、反方审稿没有句子可审(反方审稿记 no_claims 直通),正式运行照样出具,界面上整篇显示成代码
...
报告节点的 compose 统一先过 _unfenced:第一稿、重写稿、裁判退回的改写稿都经过它。只在拿得准时去——去掉首尾空白后第一行是围栏(``` 或 ~~~)、信息串为空或 markdown / md(大小写不敏感),最后一行是同种符号、同样长的收尾围栏,中间没有同种、不比它短的围栏行;信息串是 sql、json 等别的语言、围栏外有前言结语、有多个代码块、开闭围栏对不上、里面嵌着同样长或更长的同种围栏的,原样交给 compose_doc(返回的就是原字符串,文档哈希不变)。正文自己的代码块套在更长的围栏或另一种符号里时照常去掉外层,里面的原样留下。doc["source"] 记去掉围栏之后的正文,markdown 由它渲染,出口契约复核取回的也是这份文档
测试:各种去与不去的写法逐条钉住(每条判断各做过一次去掉、测试变红);节点里裸数字照样标出、引用照常渲染、重写稿同样处理、别的代码块原样不动;端到端(虚构 SQLite 源)带围栏的报告里单元格引用照常解析,裁判两句都判、反方审稿两句都审,出口完整出具
2026-10-06 12:44:44 +08:00
ThearchyHelios
898bd8a276
审批质询遮罩收口:模块说明和取质询工件的说明写上 SQL 检查结果的片段照 SQL 换
...
上一处改动(f0e97f6)只在接口说明和 _masked_checks 里写了,模块说明的「读取」一条和 inquiry_artifact 的说明补上,免得读的人以为工件里的 checks 原样给。
2026-10-06 12:34:55 +08:00
ThearchyHelios
8ca750d7ee
审批质询遮罩收口:说明跟上实现——「夹住」越过的连接词含异或、条件长到细看不过来时多遮几个阈值写进已知局限
...
- 模块说明的已知局限补一句:条件长到细看不过来(PIN_WORK)时,两边都隔开的一律按夹住算,会多遮几个阈值
- 测试说明对齐:同一个条件里夹住的那组用例越过的连接词含异或(XOR 用例),HAVING 的用例已挪到自己那条测试;年龄段那条
补上说明
2026-10-06 12:32:48 +08:00
ThearchyHelios
f0e97f614f
审批质询遮罩收口(后端):质询工件里的 SQL 检查结果字段照证据面板,片段里的遮罩值照 SQL 换掉
...
做项 3 时发现的同一类缺口:agent 的查询快照带着 SQL 检查结果(数据源查询工具对照数据目录查出的问题,checks),质询工件接口
原样带出——sql_excerpt 是从这条 SQL 摘的片段(按遮罩列筛选的那个条件,例如 buyer_phone = '13900000001'),for_model 是给模型
的改法、也照抄了片段。事件和工件里的 content.sql 已经换掉遮罩值,旁边的片段没换,等于从旁边把值露出来;证据面板对报告快照
本来就只给约定的几个字段、不给 for_model。
- inquiry_artifact 里的 checks 经 _masked_checks:字段照证据面板的 _query_checks(不交 for_model),sql_excerpt 照查询清单的
SQL 换(_scrub_sql,和遮罩列做等值比较的短的数、日期这样的字也认得出)
- 界面不读 checks,只是接口上不再带原值
- 补单元测试和端到端测试(把 SQL 检查换成会摘出遮罩值片段的假检查)。做过去掉实现、测试变红的验证
2026-10-06 12:30:52 +08:00
ThearchyHelios
32c3119086
审批质询遮罩收口(后端):质询工件里文字格夹着的遮罩值按子串换掉,回答一路照旧整份不交
...
第 1 轮起留着的缺口:备注列(没设遮罩)一格写着「客户13900000001来电改址」,手机号设了遮罩、被报告取数选中。agent 引用这一格,
回答被正确拦下(「回答中含有设了遮罩的值……已不予展示」),可事件的 inquiry_artifacts 照样记着这份快照,
GET /api/runs/{id}/inquiries/artifacts/{artifact_id} 返回原样的格子、masked 为空,等于在「不予展示」旁边一点就能看到原值。
- _masked_view 加 embedded:没设遮罩的列里,一格文字(JSON 列按界面画出来的样子)夹着按值认得出的遮罩值,把那一截换成
「已遮罩」,这一格别的字、别的格子照原样;门槛同整格(_Secrets.scrub:够长的数、两个字以上的文字,提问人自己写的、报告
列出的指标和运行输入的值不换)。这一列不记进 masked:界面把记进去的列整列画成「已遮罩」,这一列在数据源里也没设遮罩
- 只有取质询工件这一路按子串换,而且只换要取的那一份(_plan 的 embedded 是工件 id 的集合);回答一路不动,渲染出来露了
照旧整份不交
- 接口说明写清 masked 的含义:有格子整格被遮掉的列;一格文字里夹着的只换那一截,列不记进去
- 补单元测试(文字格、字典形状的行、JSON 列、整格照旧整格换、回答一路照旧)和端到端测试(回答整份不交,工件里那一格变成
「客户已遮罩来电改址」、其余格子照原样、masked 为空)。做过去掉实现、测试变红的验证
2026-10-06 12:25:48 +08:00
ThearchyHelios
4690063f5d
审批质询遮罩收口(后端):「夹住某一个值」只在同一个条件里、按条件合起来的真假认;阈值只在同一个数在这条 SQL 别处确实换掉时才不留
...
复验留下的两条多遮回归(遮得太多,不漏):
- _pinned 收全句所有范围比较一起配对,列名认不出的(SUM(amount)、函数)还和哪一列都配:分档的两个 WHEN 分支、两个选出列、
UNION 两支、WHERE 和 HAVING 各写一边,共用的边界被当成「夹住了某一笔」遮掉,回答里「以 20000 元为界」也跟着遮。改成从每个
比较往上只越过且、或、非、异或、括号,走到同一个条件根的才放在一起看;同一个条件里两边都被隔开了,再按条件合起来的真假看
是不是真只认这一个值(条件里别的部分当成不知道真假,有一种取法夹住就算)。BETWEEN v AND v、>= v AND <= v、> v OR < v、
整数的半开区间照旧认得出;age > 31 AND age <= 25 AND 25 < age AND age NOT BETWEEN 25 AND 31 这种谁也找不着的不算,第 2 轮的
原输入恢复并通过。列名认不出的只和写得一样的表达式配
- 夹住的值另记下来:两头都不是那个值的整数开区间(age > 24 AND age < 26)按夹住的 25 换,不再留着 24、26 等于写出 25
- 几百个条件连成一长串:条件改成不递归地算(以前上千层会超过递归深度,退回按词认,短的数就漏了);细看夹没夹住按步数设了
上限(PIN_WORK),看不过来的两边都隔开就按夹住算
- _literals 的「别处出现过同一个数」从所有非保留字面量里抽数字片段,日期里的 31、天数修饰里的 30、标签里的 30、没设遮罩的
列上的 amount = 30 都算,阈值就改记成等值遮掉,可那些地方一个字没换,回答正文又照样写着它。改成和真去换的同一套判断
(_swap_literal,_scrub_sql 也照它换):只有同一个数在这条 SQL 别处确实被换掉了(等值、别处的长数整个换掉,字符串里按值
换掉的遮罩数)才不留;换掉的是文字标签不牵连阈值。查询之间的正文免遮(_shown_literals)同理,按查询各自认遮罩列的比较
- 模块说明补上已知局限:按值认的门槛两头都有误差(短的数在正文里遮不住、5 位以上的数会误遮巧合的数)、遮罩数值列的
SUM/AVG/MIN/MAX 和按遮罩列分档的 CASE 标签算派生值(产品取舍,保持现状)、「夹住」只在同一个条件里认(拆进子查询或 CTE 的
认不出)、遮罩值收集有上限
- 补单元测试和端到端测试:重叠的分档边界(两个 WHEN 分支、两个选出列、UNION 两支、年龄段)、日期、天数、标签、未遮罩列的
等值照原样封存、正文不遮;同一条件里夹住一个值的几种写法(旁边有别的条件、CASE WHEN、HAVING 里同一个汇总值、整数开区间、
XOR)和别处确实换掉的同一个数照旧遮。每处改动都做过去掉实现、测试变红的验证
2026-10-06 12:24:54 +08:00
ThearchyHelios
3843a1cd89
双盲复算按需算任意快照的遮罩:按位置取自另一份快照遮罩列的输入不再当字面量交给盲算
...
- 预检以前只为 cell() 输入的快照算遮罩。口径卡上按位置取的一格(vars.res.rows[0][0])若来自另一份快照,重算
认不出它在遮罩列上,指标照常盲算,遮罩值作为字面量写进了交给盲算模型的计算式。现在 _plan_metric 对这类输入
顺着取值链认出取自哪份快照的哪一列(recompute.input_origin,和证据面板、推演、可验证报告同一个认法),按需
算那份快照的遮罩交给重算的预检:取自遮罩列的按无法复算记缺口(原因同同一份快照上的那种);那份快照读不出来、
数据源现在的遮罩又没遮这一列的,查询当时记下的遮罩无从核对,同样按无法复算记,原因说清。
- _Sources.hidden 改用证据面板那一套(api/evidence 的 _Masks、_merge_masks、_recorded_masks):合并查询也按它
合并的几个数据源算,快照读不出来时按取值链上带着的数据源名算,结果按快照记下来不重复查。
- 两个遮罩分组用例换一对盲算 SQL(不分组、按下单日筛):收窄的话说明和对照里会带出「region = '华东'」;照整条比
时说明是「时间列 + 另有未能归纳的差异」、对照里留着 GROUP BY,以此断言没有收窄,替换失效的「差异不止一条」。
去掉 _narrowed 的遮罩判断后三个遮罩分组用例都变红。
- 补用例:两份快照(cell() 取 A、按位置取 B 的遮罩列)不盲算、取值不进任务和产出,没设遮罩时照常盲算;快照读不
出来时的两种情况;时间列声明成文本的库,审批卡预告不记、真写跳过的原因和预告一字不差。
2026-10-06 12:11:50 +08:00
ThearchyHelios
314dd1248a
双盲复算写业务日期加类型门槛:两边的时间列都得在表结构里声明为日期 / 时间类型才记
...
- dual_check_facts._business_date 收下 derive 交来的表结构:两边按时间筛的列都要声明为 DATE、DATETIME、
TIMESTAMP、TIMESTAMPTZ、TIME(带精度、带时区的写法也算,大小写不论)。文本(SQLite 常把日期存成文字)、
整数(Unix 秒、20260901 这类日期键)、表结构里查不到、没声明类型的都不记,原因说清是哪一边的哪一列。
差异说明认时间列只看列名和常量像不像日期,这道门槛补上 sql_semantics 模块说明里写明的约定。审批卡上的
预告和真写共用 derive,逐字跟着变。
- 测试的表结构和虚构库(dual_check_shop.build)把下单日、支付日声明成 DATE,另可建声明成文本的一份;补门槛
的正反例:各种日期 / 时间类型的写法、文本、整数、缺列、没有表结构、表结构里写成大写、预告同一套判断。
- 修两个已知失败:跨两张表的条件、同一列的时间范围,收尾版差异说明只给兜底,改成断言兜底且不写;derive 里
「只涉及一张表」那道检查从 SQL 走不到了,改用直接构造的差异说明单测;「其他方面」换成真能说出具体方面的
关联方式(LEFT JOIN 对内连接),断言不写、原因说清差在关联;表不在表结构里那条改用有效记录条件,仍走
derive 自己的认表检查。
2026-10-06 12:11:08 +08:00
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
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
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
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
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
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
2db83a69e8
审批质询:只有空串算没指明句子、审批卡,0、false 这类照样报格式不对;结果相同的两次查询共用一份快照,引用列表里只记一次
2026-10-05 18:58:41 +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
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
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
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