ThearchyHelios
1e95f41a10
报告导出成 HTML 时,升级前写的老文档里取自遮罩列的指标写「已遮罩」:正文引用了、证据目录里却还带着原值的那几个,按可验证报告认老文档的同一个判断(certain_masks + bundle/build.py 的 withheld_metric_aliases,只认确定取自遮罩列的)照现在的报告撰写节点的写法改写,正文、按钮提示和出处链里都不出现原值;普通指标照常,现在写的文档本来就是「已遮罩」
2026-10-13 10:04:30 +08:00
ThearchyHelios
06b2c2b8ae
合入报告导出为自包含 HTML(数字点得开口径、来源、计算方式)与可验证报告数字详情里的口径卡一节;和可验证报告的遮罩改造合并:口径卡只给 id 的规则(有指标的值取自遮罩列、文档里写成「已遮罩」的)照旧,随文件附带的卡才附上它的输入指向的查询快照;数字详情保留显示文字核对和超过 2^53 的数照 JSON 原文显示,口径卡一节里输入的值同样照原文;样本页从 16 份变成 17 份
2026-10-13 10:03:24 +08:00
ThearchyHelios
7589c350bd
期 5 验收修复 N1 第 4 轮:转抄上游口径卡按整张卡、每一次执行认(保守规则);显示文字白名单收紧复核点名的几类,软换行和金额符号不再误伤
...
复核第 3 轮(91aa34d)找到三处 major、两处 minor:循环里卡转抄自己上一轮、更早一轮取过号码(SQL 带模板)时,写作目录只看
运行状态里最后一次的产出,号码进了报告正文和成果,自查通过、正式运行成功,封存之后的面板才写「已遮罩」;整张卡、清单文字、
下标不是字面量的转抄只按值认,由遮罩格算出来的年薪(月薪 × 12)在写作目录、报告、成果、证据面板、可验证报告里照给;显示
文字的白名单里还收着易混字(’ 当千分位、刂 当竖线、×10⁴ / T / bn / m 改量级、en dash 当负号),伪造页总览照样是绿色的
「全部通过」;先起别名再套没起别名的表达式、+phone 这类 SQL 写法认不出遮罩列;段内软换行紧挨着数字、数字前的 ¥ ¥ 被判
无法核对,原样导出的正常报告总览变成中性。
转抄的保守规则(recompute.masked_closure 的 CopyEdge.card;写作目录、报告自查、证据面板、推演、可验证报告同一个判断)
- 卡上的输入转抄上游口径卡(字面量下标、下标不是字面量、整张卡、清单文字、整份指标列表都算),只要那张卡在这次运行的任何
一次执行里有一个指标不给,转抄出来的就不给(masked,整张卡转抄不再降成 table 按值认);那张卡一个不给的指标都没有时照常,
没设遮罩的工作流、循环里累加自己上一轮的卡照给(第 3 轮修好的那条不回退)。最小不动点上按卡汇总:每张卡「有指标不给」
只从无到有、遮罩列只增不减,变一次只重认转抄它的那几个,工作量仍和边数成正比
- 每一次执行的指标集按台账认:写作目录(withheld_metrics)把运行状态里台账的 metric_set 条目交给 _CopyGraph(_executions,
连同它们的输入先在线程里读好),封存之后按封存范围内的台账;可验证报告(_Store._executions)按 node.finished 的台账条目
- 转抄的是哪张卡按读到的产出上记着的指标集认(经数据整形赋给变量的也认得出是哪张卡),认不出的按取值链上的节点
- 推演(recompute._copied)、证据面板(_copied_held)随之去掉整张卡转抄的 table 一档
- 行为变化:转抄了带遮罩指标的卡的普通指标(客户数、数指标个数、清单字数)也写「已遮罩」、推演不让改,正式运行引用它判
失败;那张卡自己的普通指标照给。test_report_masked_card_copies、test_report_masked_copy_closure 里按老规则写的期望相应改了
显示文字核对(verifier.js)
- 弯撇号(U+2018、U+2019)移出常见写法的名单;偏旁形的汉字(刂冫氵亻阝扌忄犭礻衤讠钅饣纟丬)、康熙部首、部首补充、扩展
B 区以后的字不算常见写法:紧挨着数字判无法核对
- 数字后面紧接 ×、*、^ 再接数字判无法核对(新原因「后面紧接着乘号或乘方和数字」),后面那个数本身也核对过的(两个数相乘)
不算
- 数字后面紧接着、或隔着空白和左括号的英文量级写法(T、G、m、b,bn、mn、tn,thousand、million、billion、trillion)按整串
字母认,判无法核对;ms、GB 这类别的单位不算
- en dash 归入像负号的短横:紧挨在数字前面判无法核对(不判不通过),前面是数字、字母的区间照常
- 段内的换行(页面上显示成一个空格)、金额前面的「¥」「¥」收进名单
- 「(单位:万元)」、x10 这类隔着几个字或换了写法的认不出:名单只是兜底,bundle/build.py 的模块说明写明真伪以封存哈希为准
已知局限不再加规则:api/evidence.py、bundle/build.py 的模块说明写明遮罩只减少暴露、不是安全边界,列出认不出的 SQL 写法
(先起别名再套没起别名的表达式、+phone、Postgres 给没起别名的表达式起的列名、视图、自己建的函数、数据整形取出来的号码)。
验证
- 新增 tests/test_report_masked_copy_any_run.py(20 项):纯函数上的边规则(四种写法、循环三轮、之前认好的指标、读到的产出
读不出来);循环里转抄更早一轮的号码(护栏写法、只按字面量下标两种)写作目录写「已遮罩」、正式运行判失败,标注时文档、
成果、面板、可验证报告都没有号码;循环之后的卡转抄最后一轮,写作目录、面板、推演、可验证报告同一个判断,可验证报告自己
(没有报告的运行、老文档)也认;经数据整形转抄的按卡本身认;年薪的五种转抄写法写作目录都写「已遮罩」,标注时文件里没有
年薪;没碰号码列的循环、卡上没有遮罩指标的照常
- test_bundle_shown:复核点名的几类各自判无法核对、写明原因、总览中性;软换行、¥ ¥、两个核对过的数相乘、en dash 区间、
ms / GB 照常通过;PROSE 样本去掉 en dash,加上软换行和 ¥ ¥,17 处全部通过
- check-bundle 补弯撇号、刂、扩展 B 区、×10⁴、bn、billion、en dash 七种篡改(各自判无法核对、点名、总览中性),prose 样本
17 处全绿
- 复核者探针:test_probe_r3a、test_probe_r3c 的写法都拦住;test_probe_n1c(没设遮罩的循环自引用)照常;layout_probe 的
108 种写法里点名的几类都判无法核对,¥ ¥ 照常通过;Chrome 断网打开 forge3、forge4 的伪造页,点名的几类都不是绿的、提示
都显示
- 开发数据 39 份报告 1591 处、验收数据 58 份 1695 处引用按新规则扫过,判不通过和无法核对都是 0
- 每处改动都做了「去掉实现、测试变红」:17 个定点变异(不看整张卡、不读每一次执行、写作目录不交台账、可验证报告不读每一次
执行、整张卡退回按值认、推演不认、按取值链上的节点认卡两处;弯撇号、偏旁、扩展 B 区、乘号乘方、英文量级、en dash、软换行、
¥ ¥、两数相乘豁免)全部变红
2026-10-12 23:01:09 +08:00
ThearchyHelios
91aa34d014
期 5 验收修复 N1 第 3 轮:转抄上游口径卡的遮罩改在指标依赖图上一次算出最小不动点;显示文字核对紧挨着的字改成白名单
...
复核第 2 轮(ce71f7d)找到两处 major、两处 minor:转抄的识别逐个往上递归、追够八层(CARD_DEPTH)就按遮罩算——没设任何遮罩
的工作流里,循环里累加自己上一轮产出的口径卡在写作目录里指回自己,一直追到八层,写成「已遮罩」,正式运行判失败、报错说
「取自设置了遮罩的列」;每个指标的护栏 nodes.acc 选中整张卡的全部指标,递归次数约为(指标数 + 1)的八次方,四个指标四十秒、
卡住事件循环;封存之后循环超过八轮的,证据面板写「已遮罩」,可验证报告把文档整份只给哈希。紧挨着改字仍是黑名单:西里尔、
希腊的 I、O、M、K,汉字「丨」,换行、制表、各种宽度的空格后接「万」,「(万元)」,负号前面放一个别的文字系统里长得像撇号的
字母,都还是绿色的「全部通过」、提示也不显示。另有:* 展开派生表、WITH 里没起别名的 UPPER(phone) 认不出是确定取自遮罩列,
号码进了写作目录和文档;上游卡的节点产出读不出来时转抄当作认不出出处,号码随卡 2 的节点完成事件出去了。
转抄的遮罩在指标依赖图上一次认(recompute.masked_closure,写作目录、证据面板、推演、可验证报告共用)
- 先按转抄以外的输入认每个指标(写作目录、可验证报告认老文档只按确定取自遮罩列的 sure;证据面板、推演宁可多遮),再沿转抄的
边(nodes.<卡>.metrics[i].value、vars.<assign_to>.metrics[i]、整张卡 / 清单文字 / 整份指标列表 / 下标不是字面量的连到那张卡
的全部指标)往下游传,直到不再变化。从「都照给」起往上收:环(循环里抄自己上一轮、几张卡互相转抄)本身不带来遮罩,环上有
一个指标别的输入取自遮罩格,整个环都不给。每个指标的结论只往严里变,工作量和边数成正比;删掉 CARD_DEPTH、CARD_TOO_DEEP
和逐层递归(_InputMasks._copied、_Store._copied_kind),可验证报告的缓存不再按 (卡, 指标) 混着深度记
- api/evidence.py 的 _CopyGraph(按请求记在 _Masks 上,键是 (指标集工件, 指标在卡上的位置)):写作目录只有最后一次的产出,
抄自己上一轮的卡是一个环;封存之后按每次执行认(_card_outputs,同一次执行只找一次),一次一次往回连到第一轮。bundle/build.py
的 _Store.metric_word 按同样的键各认法一张图
- 推演(api/whatif.py → copied_inputs)的转抄输入按证据面板同一张图认:转抄的是不给的指标就不给值、不能改(原因「转抄的口径卡
指标取自设置了遮罩的列」),核对不了的不给、不推演。以前只按值认,转抄来的三位数余数照给、还能改
- 上游卡当时的产出读不出来(文件不在、与哈希不一致)、卡上又记着这个输入出自口径卡、转抄来了值的,转抄核对不了(同按位置取的
一格取值链上的产出读不出来),可验证报告里卡 2 只给哈希;第一轮还没有上一轮(转抄来的是空值)的不算
- 可验证报告附带口径卡另看卡上记着的转抄值(_copies_masked):转抄的是不给、核对不了的指标,或者整张卡、清单文字转抄来的值里
写着号码(len(nodes.card.text) 的输入就是整段清单文字),卡只给 id。指标的值照给时以前照常附带
- 确定取自遮罩列(_sure)在整份算的快照里另按列名认(_named_from_masks):SQLite、MySQL 拿没起别名的表达式原文当列名,* 展开
派生表、WITH、UNION 一支时原样带出;按列名拼一条只选这一项的 SQL 交给同一套认,COUNT(phone)、FILTER、分档标签照旧不算。
单元格引用的自查、收遮罩值、裁判摘录跟着收紧
显示文字核对(verifier.js):紧挨着数字头尾的那一个字改成白名单(COMMON)
- 名单:汉字(含「一」,去掉丨、丶、丿这类笔画字)、中文标点、半角和全角空格、ASCII 字母、常用半角标点和 = + / ~ * # < > 等
算式符号、× ÷ ≈ ≤ ≥、上一轮放行的破折号写法(——、—、–、―、﹘、ー、─、〜、〰);逗号、句点、连字符看上下文(句点在数字头
前面只认 NO. 这种字母缩写)。名单以外的(别的文字系统的字母、制表换行和各种宽度的空格、零宽字符、全角拉丁字母、表情)判
无法核对,原因「紧挨着这个数的字不在常见写法里,无法确认读者看到的数」,总览随之不是绿的、显示去系统里核对的提示
- 像数字的字母另收 o、竖线一类(|、|、丨、竖排破折号、制表符竖线、拉丁 / 西里尔 / 希腊里长得像 l、I 的)和圆圈一类(西里尔、
希腊的 O、空心圆);量级单位另收十、拾、佰、仟和当「万」用的 w、W,前面隔着的改成任何空白和左括号、左引号(「(万元)」)
- 负号前面的「编号」例外只认 ASCII 字母数字;后面接 e 和数字(科学记数法)同紧挨着数字,判不通过
- 开发数据 39 份报告 1591 处、验收数据 58 份报告 1695 处引用按新规则扫过,没有一处判不通过或无法核对;prose、formats 样本原样
导出全绿,别的样本页总览和第 2 轮一字不差;复核者的 42 种伪造写法(forge.py、forge2.py)全部不是绿色、提示都显示
测试
- 新增 tests/test_report_masked_copy_closure.py:没设遮罩的循环自引用照常显示、正式运行成功(复核者的探针);循环三轮、十轮的
老文档照常附带;两张卡互相转抄照给;环上一个输入取自号码列整个环都不给、同循环里不相干的卡照给;上游产出读不出来三种转抄
写法都不漏号码;卡上记着转抄清单文字的卡不附带;推演按同一张图认转抄输入;* 展开里没起别名的号码表达式八种写法算确定取自
遮罩列、只数个数和分档标签的不算;纯函数的环、整张卡转抄、读不出来、两千个指标线性;写作目录和可验证报告在三张卡各 8 个
指标、循环十轮时各一秒以内(写作目录每个指标只认一次),另有真跑两张卡各 8 个指标十轮的计时
- test_report_masked_card_copies:认转抄补读不出来的几种;「追不到头按遮罩」改成环上认(没别的输入照给、有号码输入整个环不给)
- test_bundle_shown:名单以外的字、像数字的字母、隔着各种空白和左括号的量级单位、别的文字系统字母后的负号、科学记数法各自判
无法核对或不通过、总览不是绿的;常见半角标点、算式符号照常通过;表情紧挨着数字改判无法核对(隔一个空格照常通过)
- check-bundle 补长得像 I、M 的西里尔字母、汉字「丨」、数学粗体 l、隔着细空格的一位数、开尔文符号、隔着换行和 em 空格的「万」、
「(万元)」判无法核对,撇号字母后的负号、e3 判不通过,各自点名、总览不是绿的
- 每处改动都做了「去掉实现、测试变红」:整套退回第 2 轮(27 项红、写作目录计时十秒没认完、可验证报告长循环把文档只给哈希);
环按遮罩算、不沿边往下游传、读不出来当认不出出处、不看卡上的转抄值、不按列名认、推演不用依赖图、每个指标各建一张图;名单
不判、名单去掉等号、不去笔画字、像数字的字母不扩、量级单位前只隔空格、负号例外按文字区、科学记数法不算、单位不收十和 w、
句点不看前面是不是字母
2026-10-12 21:12:57 +08:00
ThearchyHelios
ce71f7d5c1
期 5 验收修复 N1 第 2 轮:取自遮罩格的指标只按确定取自遮罩列的认、转抄上游口径卡的也认;显示文字核对不误判正常写法,总览有一项无法核对就不给绿色的通过
...
复核第 1 轮(abb2707)找到四处:写作目录按证据面板宁可多遮的那一套认指标出处,SQL 认不准时没碰号码列的销售额也成了
「已遮罩」,正式运行引用它就判失败(相对基线回退);「紧挨着负号」连破折号「——」「—」和汉字「一」都算,「运费统一10元」
「合计——7,036.50元」原样导出变红(相对基线回退);紧挨着改字只堵住了数字、负号、小数点,接「万」、画删除线、从右往左
书写的字母、l / I / O 照样全绿,根子在总览把无法核对的项也给绿色;第二张口径卡转抄遮罩指标(nodes.<卡>.metrics[0].value、
vars.<assign_to>.metrics[0].value、nodes.<卡>.text)时号码照样进写作目录、文档证据目录和可验证报告。
取自遮罩格的指标只按确定的那一套认(写作目录、报告自查、可验证报告同一个判断)
- 写作目录(api/evidence.py 的 withheld_metrics)认指标出处时遮罩列只认确定取自遮罩列的(_InputMasks 的 sure:读得出来的
快照按单元格引用自查的 _cited_masks,读不出来的按数据源现在设的列名),和 [[v:…]] 引用同一格的自查同一个口径:WITH 写了
列名表、VALUES 当表、子查询里有没起别名的号码表达式、只装着分档标签的列,指标照常显示、照常引用;改了名字、套了函数的
号码列照旧「已遮罩」。证据面板、推演照旧宁可多遮。报告自查按目录里记的 masked 认,跟着同一个判断
- 可验证报告认老文档(证据目录里还写着原值,整份只给哈希)按同一个判断:api/bundle.py 先按证据面板的那一套认好每份查询
快照里确定取自遮罩列的列和这次运行查到过的遮罩值(certain_masks),交给 build_bundle(sure_columns、sure_secrets),
_Store.metric_word 的 sure 按它们认。认口径卡能不能随文件附带照旧宁可多遮(卡上记着输入的值),SQL 认不准的卡同基线只给 id
转抄上游口径卡的指标按上游那个指标认
- recompute.card_input 认出输入转抄了哪张卡的哪几个指标:nodes.<卡>.metrics[i].value、vars.<卡的 assign_to>.metrics[i]、
整个指标、输入、渲染算转抄那个指标;整张卡、清单文字、整份指标列表、下标不是字面量的同整份查询结果(值里有遮罩值才不给,
数指标个数的照给);只取名称、单位、口径名的不算
- 证据面板 / 写作目录(_InputMasks._copied)、可验证报告(_Store._copied_kind)都用同一个 _metric_masks / metric_word 往上追,
上游取自遮罩格,转抄的也不给;追了 CARD_DEPTH(8)张还没追到头(循环里抄自己上一轮的产出)的宁可多遮
- 写作目录读快照前把运行状态里每张口径卡的输入一并读好,不在事件循环里读盘
显示文字核对(verifier.js)
- 判不通过只剩紧挨着的数字、小数点,和真当负号用的三个(半角连字符减号、数学减号、全角减号)紧挨着数字开头、前面又不是
字母数字时(「SKU-12」「A-3」的连字符是编号的一部分)。破折号(——、—、–、―,小号的、竖排的)、波浪线、汉字「一」、
假名长音、制表符横线这些易混字当普通的字。连字符、不断行连字符、上下标负号、粗减号这类平时不当负号用的短横紧挨着数字
开头判无法核对(以前判不通过;基线也是无法核对)
- 判无法核对(带原因):后面接着量级单位(万、亿、千、百、兆、萬、億、%、‰、‱、k、K、M、B 及全角,中间隔着空格也算;
核对过的字以「万」「亿」结尾再接一个也算),核对过的字画着删除线或紧挨着画了删除线的字,紧挨着长得像数字的字母和数字
符号(l、I、O、上下标数字、圈码、罗马数字、汉字〇),从右往左书写的字母和方向控制字符(照旧)
- 总览(overallOf):一项无法核对都没有、每份报告都核对上才是绿色的「全部通过」;有无法核对的写中性的「可核对的项全部通过,
另有 N 项无法核对」,下面醒目地写明这个文件判断不了真伪,要在系统中核对封存(运行 ID、GET /api/runs/<id>/verify、定时任务
通知里的清单哈希前 12 位)。以前无法核对的项照样给绿色,伪造者只要让读者看到的那个数落进无法核对就行
- 交出 layoutOf 给 node 里逐条核排法;开发数据 39 份报告 1591 处、验收数据 58 份报告 1695 处引用按新规则扫过,没有一处判
不通过或无法核对
测试
- 新增 tests/test_report_masked_metric_sure.py(四种 SQL 认不准的销售额、分档标签照给照引、确定取自号码列的照旧遮、老文档
照常附带、写作目录和可验证报告逐个指标同一个判断)、tests/test_report_masked_card_copies.py(三种转抄写法在写作目录、文档、
自查、证据面板、可验证报告里都不给号码,没有报告的运行、老文档,转抄普通指标照给,认转抄的各种写法,追不到头的宁可多遮)、
tests/test_bundle_prose_export.py(「统一」「——」「—」「SKU-」「共…家」「–」真跑报告撰写节点、从接口导出,全部通过、总览绿)
- test_bundle_shown:负号只认三个、前面是汉字的照判不通过;像负号的短横、量级单位、删除线、长得像数字的字母各自判无法核对、
总览中性;正常写法原样导出全绿;总览只在一项无法核对都没有时是绿的
- 样本页新增 prose(写作者自己写在引用旁边的普通文字,原样导出全绿);check-bundle 补数学减号、紧挨着汉字加负号判不通过,
接万(隔空格)、接亿元、接 %、接 k、订单号接万、画删除线另写一个数、前面加小写 L、后面接大写 O、长得像负号的连字符判无法
核对,各自点名原因、总览中性并写明去系统里核对;有无法核对项的样本页(base、legacy、continued、missing-card、masked-card、
masked-source、nan)总览改断言中性,从右往左书写的字母那条不再断言总览是绿的
- 每处改动都做了「去掉实现、测试变红」:写作目录不用 sure、老文档不用 sure、sure 列不用、转抄认不出(三处各自)、追不到头
按核对不了、负号的字母数字例外、负号恢复成 \p{Pd} 全部、数学减号全角减号不算、量级单位、隔空格、以万结尾、删除线、像数字
的字母、像负号的短横、总览有无法核对照样绿
2026-10-12 19:09:50 +08:00
ThearchyHelios
abb2707904
期 5 验收修复 N1:取自遮罩格的口径卡指标不进报告文档和可验证报告;显示文字核对堵住紧挨着改字的绕过
...
验收第二轮发现:口径卡 phone_raw = cell(q_cust, 0, 'phone') 被 [[m:phone_raw]] 引用时自查不拦,号码写进正文;写作目录、
文档的证据目录收着上游口径卡的全部指标和原值;可验证报告里口径卡的节点完成事件(预览逐条写着「指标(名称)= 值」)一律
附规范串,没有报告的运行也照样带出号码;另外只改紧挨着被引用数字的普通正文(前面补一位数、加负号、后面接「0 万」)、重算
全部哈希,读者看到的是另一个数,核对页只标无法核对,总览仍是绿的。
报告撰写节点
- 写作之前按证据面板指标步骤的那一套认出值取自遮罩格的指标(api/evidence.py 的 withheld_metrics → _metric_masks,
recompute.withheld_value):cell() 取的遮罩格、改了名字的遮罩列、按位置取的一格一行、整份结果里带着遮罩值的。写作
目录、存进文档的证据目录里这些指标的值、渲染、标签都写「已遮罩」并记 masked(evidence.withhold_metrics,没被引用的
也一样),写作目录另说不要引用
- 只按出处认(by_value=False):认不出出处、值碰巧等于遮罩列某一格的普通指标(写死的目标 20000)不算,不然它在报告里
成了「已遮罩」、引用它的正式运行判失败、写作者也改不掉(自查第 3 轮去掉按值认是同一个道理);证据面板展示上照旧多遮
- 引用这类指标照样解析、正文写「已遮罩」(换算不再算),自查记 masked_cell(evidence.masked_metrics),和引用遮罩格同一
套处置:交回重写,仍不改按「违规处置」办;缺口、日志、判失败的下一步说「指标」
- 写成「已遮罩」的别名记进节点产出(masked_metrics),出口契约复核按同一份重建目录(report_catalog),正文里的「已遮罩」
对得上,不说文档被改过;写作时按上游状态建目录,循环里重跑不沿用上一次记下的那份
- 证据面板点开这一处:值、渲染都是「已遮罩」,按文档写的比渲染,不报渲染不一致
可验证报告(bundle/build.py、verifier.js)
- 口径卡的节点完成事件:卡只给 id(有输入取自遮罩列,或者有指标的值不给)的只给哈希,和报告引不引用无关;没有台账的
老运行按预览里的 artifact、节点产出工件认,都读不出来的按运行里有没有带遮罩的快照
- 卡只给 id 的判断另按指标认(_Store.metric_word,和写作目录同一个判断):整行、下标不是字面量的一格、整份结果转成的
文字,以前只认字面量下标的一格,卡原样嵌了进去
- 证据目录里还写着这类原值的老文档(升级前生成的,或者生成之后数据源才设的遮罩)整份只给哈希、不附带它引用的工件,
报告节点的完成事件也只给哈希;快照读不出来时按它的数据源现在设的遮罩认,卡读不出来时按这次运行查到过的遮罩值认。
核对页照实说明原因(中性色),这份报告算未能核对,总览不是绿的;文档里写成「已遮罩」的指标所在的卡一律只给 id
- 被引用的数字紧挨着(中间没有空白、标点)数字、负号、小数点判不通过,点名「正文里紧挨着这个数的字改变了读者看到的
数」;排在看不见、改变方向的字前面判,同一句里再放一个这种字也降不成无法核对。服务端组装的文档两个数之间补了空格,
原样导出照旧全绿(开发数据里 39 份报告、505 处引用,没有一处紧挨着)
测试
- 新增 tests/test_report_masked_metrics.py(目录、自查、重写、标注 / 失败、出口契约、证据面板、循环)、
tests/test_bundle_masked_metrics.py(没有报告的运行、新文档、老文档连同核对页、普通卡、和写作目录同一个判断、手搭的
几条分支);样本页 masked-card 改成现在的报告撰写节点写的文档,新增 masked-old-doc;check-bundle 补数字前加数字、加
负号、后面接「0 万」三种篡改,各自变红、点名,原有的紧挨着补位、连字符两条改成不通过,报告文档标成遮罩那条改成总览
不是绿的
- test_report_masked_values 的 [[m:phone_raw]] 改成按出处拦、写死的热线号码照常引用;几处按旧的报告正文(「13位」
「11位」「26位」)找片段的测试改成按引用找(test_evidence_metric_masks、test_evidence_masked_aliases、
test_whatif_masked_values),断言照新的正文写
2026-10-12 17:23:27 +08:00
ThearchyHelios
d177289a53
合入 M2 与 K3b 之后的整合修正:报告自查、裁判摘录、收遮罩值认「确定取自遮罩列」时直接用 masking._derived_masks 交回的 whole / collect,不再在结果后面垫一列去探测整份算——K3b 把「没有 * 的一支、列数和结果对不上」也判整份之后,垫过的每条 SQL 都成了整份算,没起别名的 UPPER(phone) 一个值都收不到、裁判摘录里照给号码、引用它的报告照常出具;UNION 后一支是 * 的写法也一并认对
2026-10-12 14:19:41 +08:00
ThearchyHelios
7cec3079f0
合入期 5 验收修复 M2:证据面板与推演按 SQL 认出改了名字的遮罩列;推演里取自遮罩格的指标不露原值;报告自查拦下引用遮罩列的格子(按列名对整个数据源生效,和证据面板同一个口径);结论句裁判的摘录按快照逐份遮确定取自遮罩列的列;片段接口在没开结论句裁判时照实说;遮罩分析按快照工件 id 缓存
2026-10-12 14:17:45 +08:00
ThearchyHelios
1cfa5a524d
M2 复核第 4 轮:报告自查认遮罩列和证据面板同一个口径,哪张表(含视图)里叫这个名字的列都算;结论句裁判的摘录按快照逐份遮确定取自遮罩列的列;没起别名、盖住全部结果列的表达式算确定取自遮罩列,值照收
...
第 3 轮的「遮罩表」推断和退回的裁判摘录各开了一个口子,收值时又把按位置认得出的列丢了:
- 报告自查去掉「遮罩表」推断(_mask_owners)。数据源的 mask_columns 只认列名、不支持写成「表.列」,按列名在整个数据源上
生效:引用的那一格按 SQL 认出取自任何一张表里叫这个名字的列就记 masked_cell,视图(customer_spend.name)、没有第二个
遮罩列的表(employees.name)、门店名(stores.name)都算,和证据面板的遮法一致。以前经视图引用客户姓名、引用店员姓名,
正式运行照常成功,姓名写进了报告。SQL 血缘只用来点名出处,和排除值确实取自普通表别的列的(SELECT region AS phone
FROM stores);视图、表结构里没有的表、写了别的库名的表、没标 is_view 的老表结构、没有冻结表结构的快照看不出列的出处,
照算(_frozen_schema 只把 is_view 明写为 false 的表当普通表)。违规说明照实写取自哪张表的哪一列:「列「store」按 SQL
认出取自 stores.name,数据源对列名「name」设置了遮罩(按列名对所有表生效)」
- 交给结论句裁判的摘录按快照逐份遮(api/evidence.py 的 _judge_loader):每份快照里确定取自遮罩列的列(_mask_sets 的
sure)并进交给 judge.prepare 的那一份快照的 mask_columns(工件本身不动),裁判照它自己的办法遮掉,judge.py 不用改。
c.phone AS tel 的号码不再进摘录;不按数据源名合并(另一份快照里同名、取自门店热线的列照给),不用宁可多遮的 hidden
(整份遮的快照、只数个数的列照给)。按需裁判和报告撰写节点里当场裁判同一个函数。摘录变了的句子复用键随之变,此前
判过的会重判一次
- 收「这次运行查到过的遮罩值」:_sure 以前凡是要遮的列盖住了全部结果列、名字又对不上,就当认不准、整份算,
SELECT UPPER(phone) FROM customers 一个值都收不到,证据面板之后照原样显示 SQL 里写着的号码。现在结果后面垫一列再认一遍
(_whole),垫的那一列也算进来的才是整份算的;按位置认得出的照收,整份遮的照旧只遮显示、不收值
测试:test_report_masked_owners.py 改名 test_report_masked_any_table.py 并按新口径改写(经视图改名 / 不改名、店员、门店名、
客户名真跑判失败且成果里没有值;* 展开、WITH、UNION、视图里改成遮罩列名字的列、没有表结构、没标 is_view、表结构里没有的
表、写了库名的表);新增 test_judge_excerpt_masks.py(按需、当场两条路的摘录都不给改了名字的号码列,同名的门店热线照给;
没起别名的 UPPER(phone) 摘录也不给);test_evidence_mask_memo.py 加没起别名的表达式照收值;违规说明的断言跟着改
2026-10-12 13:50:31 +08:00
ThearchyHelios
65d6a1e63c
M2 复核第 3 轮:报告自查只查引用、别的表里同名的列不算;裁判摘录退回只按数据源设的遮罩列;收遮罩值只收确定取自遮罩列的值;遮罩分析和收到的值按快照工件记在进程里
...
第 2 轮的按值自查和面板那套宁可多遮的认法带进了误判,正式运行因此失败,代价远大于收益,这一轮回到规格原意:
- 报告自查去掉按值在正文里找遮罩值(engine/evidence.py 的 masked_values、report.py 的收值):两个字的姓名会撞上「销售
高峰」这类常用词,同名列的值会撞上门店名;照抄成正文的号码本来就会被「数字没有出处」拦下。时间线日志 report_masked_cell
不再带 written,decode.ts、terms.ts、证据审计的 CSV 回到「引用了遮罩列」一种说法,check-decode 同步
- 自查认引用时从 _mask_sets 的 sure 起,再按 SQL 血缘(sqlglot.lineage,按快照里冻结的表结构)核一遍值取自哪张表的哪一列
(api/evidence.py 的 _cited_masks / _owned_columns):遮罩列不带表名,同名的列在几张表里都有、其中有的表另有别的遮罩列时
(customers 有 name 和 phone,stores 只有 name),只认那几张表,门店名不算客户姓名;值根本不取自遮罩列的(region AS
phone)也不算。认不出出处的照算,没探查过表结构的照列名认。违规说明点名它取自的那一列遮罩列
- 交给裁判的摘录退回 M2 之前的做法,只按数据源设的列名遮(删掉 _judge_masks):并进面板那套宁可多遮的列后,整份遮的快照、
只数个数的列从摘录里消失,被引用的金额、人数裁判看不到。按需裁判和节点里当场裁判都改回
- 证据面板、推演收「这次运行查到过的遮罩值」只收 sure 的列(_snapshot_secrets,同 masking 收值的口径):SQL 认不准、整份
遮的快照只遮显示,里面的区域名、金额不再收成遮罩值
- 按快照工件 id 在进程里记下遮罩分析和收到的值(_SnapshotMemo,键里带数据源现在设的遮罩、在不在、类型,设置改了不拿旧的;
只记读得出来的快照,存取加锁,分析结果冻结、交出去的值另抄一份):之后点开片段、推演都不再把全部快照读盘、复验、分析,
只读这一步要显示的那一份。30 份 500 行的快照,第一次约 0.7 秒,之后不到 1 毫秒
测试:新增 test_report_masked_owners.py(高峰、门店名写成文字照常出具,照抄号码由数字核对拦下,引用门店名不算、引用客户名算,
同一条查询里两张表的同名列、只设 name、* 展开、WITH、UNION、没有表结构、表值函数)、test_evidence_mask_memo.py(整份遮
的快照不收值、只读一次只分析一次、设置改了重新收、推演共用、再点开片段只读本步快照);裁判摘录改测被引用的金额和计数
都在摘录里;按值自查的用例改成不按值认的回归
2026-10-12 12:33:32 +08:00
ThearchyHelios
ce4be9cc8f
M2 复核第 2 轮:报告自查按值认出正文里写着的遮罩值,只数个数的列不再判违规;遮没遮核对不了的输入写「无法核对」;整句面板挂的依据按证据图的标签写
...
- 自查按值认(engine/evidence.py 的 masked_values,report.py 的 _MaskedCells):写作目录里确定取自遮罩列的值出现在正文里——照抄成文字(姓名这类文字列数字核对管不到)、写成数字(换了写法的长号码组装时被拆成几个数字片段,按整句认)、经指标带出来([[m:phone_raw]] 的值就是号码)——记一条 masked_cell(by_value),不带值,交回写作者时附上值换成「已遮罩」的那一句。只收确定取自遮罩列的列、不收分档标签;运行输入里写着的值是发起运行的人自己填的,不算。只读数据源现在设了遮罩的快照,认引用时读过的不再读,没设遮罩的运行一份都不读
- 时间线:日志 report_masked_cell 多带 written(其中按值认出的几处),标题分「引用了…格子」「写进了…值」「引用、写进了…」;缺口、日志按两种分别说;违规清单、CSV 的叫法改成「写进了遮罩列的值」
- 只数个数的列(COUNT(*) FILTER (WHERE phone IS NULL)、SUM(phone IS NULL)、AVG(phone IS NOT NULL)、SUM(amount) FILTER (WHERE phone IS NOT NULL)):认遮罩列的那一套把 FILTER 条件、汇总里的真假条件当成值的来历,数据质量报告引用「手机号缺失的人数」在正式运行里判失败。自查认之前先改写(_counted:FILTER 同 WHERE 去掉,汇总里的真假条件改成 CASE WHEN … THEN 1 ELSE 0 END),不判违规;证据面板、推演照可验证报告的认法多遮(只影响展示),根上的改法在 masking 里
- 证据面板:遮没遮核对不了的输入(快照、取值链上的产出读不出来),值和代入式里写「无法核对」,不写「已遮罩」,数据源可能根本没设遮罩
- 整句面板「挂的依据」不再直接读文档目录里的「名称 = 渲染值」:按证据图的标签写(服务端已把用到遮罩列的指标值换成「已遮罩」),证据图没回来时指标只写名字
- on_demand:当场裁判过、文档里却压根没有这句的判定时,不说「原因见判定」
- 测试:合并查询自查的用例补上拼接、upper、WITH;推演对整行、下标不是字面量的一格说「用到了遮罩列」(顺着取值链认出来的,不是按值猜的);计数指标 cnt 的原值照给;SQL 认不准、只数个数的反例
2026-10-12 10:48:19 +08:00
ThearchyHelios
25011d074b
M2 复核第 1 轮:合并查询按合并 SQL 认遮罩列,报告自查只拦确定取自遮罩列的格子,推演和证据面板对指标原值同一个判断,面板认法和可验证报告同一个函数
...
接手被限流打断的第 1 轮修复,补完后提交。处理的复核发现:
- 合并查询:合并 SQL 里对遮罩列改名、套函数、拼接、汇总、经 WITH 转一道得来的结果列,以前没有逐格来历就认不出,片段接口、勾行接口原样给出号码、报告自查也漏判。现在 _merge_mask_sets 把各输入要遮的列名当作遮罩列、按 SQLite 读法认合并 SQL;输入快照读不出来又可能带着遮罩的,它的列全部当遮罩列
- 报告自查:_mask_sets 分出 hidden(面板、推演按它遮,宁可多遮)和 sure(自查按它判违规)。SQL 认不准、整份算进来的列,只装着分档标签的列不再判 masked_cell,正式运行不会因为和遮罩列无关的金额判失败;sure 按数据源自己的方言认
- 判失败的下一步:违规里有引用遮罩列的,只说去改写作指令,不建议换模型、不建议先改成标注
- 时间线、缺口不再说「这些值会随报告出具」「出具已按缺口降档」:探索运行、没设出具契约的成果不出具,只说已记为缺口
- 只读引用到的快照:报告节点组装好一稿之后只认正文引用到的那几份查询快照,认过的不再读
- 审计表、导出的 CSV 给 masked_cell 单列一行
- 推演和证据面板:指标原值给不给是同一个判断(recompute.withheld_value),输入分类同一套(input_origin 的 wide:整行、下标不是字面量的、整份结果都认)。数行数的 len(vars.res.rows) 两边都照给,str(vars.res.rows)、整行、数据整形取出来的号码两边都不给;遮没遮核对不了的写「无法核对」,不写「已遮罩」
- 认不出出处的输入按值认:值就是这次运行查到过的遮罩值的不给、不推演
- 证据图 evidence[].label 用到遮罩列的指标写「名称 = 已遮罩」
- 证据面板认遮罩列调可验证报告的那个函数(bundle/build.py 的 _derived_columns),再按数据源方言认一遍,可验证报告整份遮的面板不会照给
- 查询步骤的 SQL、合并 SQL、SQL 检查片段、合并警告里写着的遮罩值展示时换成「已遮罩」,底下写明只是展示时换的
- 交给裁判的摘录:按需裁判、节点内当场裁判都把 SQL 里改了名字的遮罩列并进数据源名下(_judge_masks)
- on_demand:当场裁判过、这句没判成(触顶、出错、被截断)时照实说没判成
2026-10-12 10:17:40 +08:00
ThearchyHelios
265ba0c91d
报告导出为自包含 HTML(数字点得开口径、来源、计算方式);可验证报告的数字详情补齐口径卡一节
...
两件事,一条心:把「网页上点数字看得到的效果」带出系统外。
① 报告导出:新增 GET /api/runs/{run_id}/report.html(app/report_export:build + 模板 + 浏览器端脚本)。
正文由服务端按报告文档的块、句、片段渲染成 HTML——不执行脚本也读得到整份报告(附件预览常常不执行脚本);
执行脚本后,带出处的数字、无证据的数字、可疑的表名字段名都点得开,面板是网页上证据面板同一个拼法的
出处链(api/evidence._chain):指标步骤带口径卡名与版本、原式、代入式、每个输入取自哪次查询的哪一格、
复算、双盲复算;查询步骤带 SQL 和被引用的行;数据源遮罩列照网页上的规矩写「已遮罩」。封存状态逐项标明;
没封存的运行照常导出(和网页上读报告一个道理)。同样的引用共用一条链,长报告不把整份快照抄几十遍。
入口在问数据答案和运行详情成果上的「导出」(带证据的报告给 HTML,Markdown 留一个小的;旧运行照旧只有
Markdown)——api.reportExport + AssistantStream 的 AnswerActions。
② 可验证报告(bundle)的数字详情补齐:点开数字原来只有出处和值,现在多一节口径卡——指标(名 + id)、
单位、原式、代入式、输入(取值 ← 路径、取自哪次查询的哪一行哪一列)、复算;输入指向的查询快照也随文件
附带(遮罩规则同嵌入那一套,build._card_input_queries),④ 引用链按「已核对的口径卡的输入」认它们
(哈希对不上的卡不认,免得替被改过的卡圆)。收件人不连服务也能看到每个数怎么算出来的。
测试:后端 tests/test_report_export.py(真跑运行导出,正文、出处链、遮罩、只读、404/409、共用链);
bundle_samples 的口径卡换成带原式/代入式/输入/复算的真实形状,另加 metric-only 样本页(只引用指标的
报告,快照从口径卡的输入这一条路附带);check-bundle 断言数字详情和这条引用链,加上篡改;新增
scripts/check-report-export.mjs(真导出断网点开、不执行脚本也读得到、成果上的导出按钮、旧答案没有
HTML 按钮、409 提示),挂进 check-all。README 补「导出两份」一节。全量 pytest 通过;check-bundle、
check-report-export、check-stream、check-evidence、check-chat 全部通过(check-runs 5 项失败为基线
上就有的沙箱数据形态问题,与本次无关)。
2026-10-10 12:59:21 +08:00
ThearchyHelios
f0b8c50647
M2 证据接口的模块说明补上新的遮罩规则:SQL 里给遮罩列起了别名、套了函数得来的结果列同样遮,用到这些列的指标,指标步骤的值也不给
2026-10-07 00:31:18 +08:00
ThearchyHelios
8e6cc8f964
M2 按需裁判接口认不出是哪份报告时(点名的不是报告撰写节点、没有封存的报告、文档读不出来)不替它说判没判过:正式运行只说「正式运行的结论句只在报告撰写节点内裁判,不能按需裁判」
2026-10-07 00:28:54 +08:00
ThearchyHelios
76fa42849c
M2 证据面板和推演认得出改了名字的遮罩列,指标本身的原值也不露:查询步骤、指标的输入、推演的勾行与遮罩、合并查询按 SQL 认取自遮罩列的结果列(c.phone AS tel 这类别名、函数、子查询、WITH),和可验证报告、核查 agent 同一套认法;用到遮罩列的指标,推演答复里的 old、rendered_old 和证据面板指标步骤的 value 写「已遮罩」
...
验收里证据面板对 c.phone AS tel 的快照给出 masked=[]、三个号码原样交出;推演把 phone_raw 判成 masked、输入置空,指标的 old 却还是那串号码。现在:
- 认遮罩列只有一个函数 api/evidence.py 的 _snapshot_masks(查询当时记下的加数据源现在设的,再经 engine/masking.py 的 _derived_hidden 按 SQL 认改了名字的;SQL 解析不了又写着遮罩列的整份遮),查询步骤、_InputMasks、推演的 _mask_of 都调它;_Masks 顺带记数据源类型,按它的方言解析
- 合并查询按逐格来历遮:输入快照里改了名字的遮罩列(输入是合并结果的再往下追)也遮到合并结果里
- 指标的原值按 recompute.hides_value 一个判断:有输入取自遮罩列(含只嵌在下标里的),或者最外层的输入遮没遮核对不了;推演结果标 withheld,报告里引用它的地方 rendered_old 同样写「已遮罩」
- 面板底下的遮罩说明改成「这些列取自数据源中设置了遮罩的列」:遮的可能是别名列
2026-10-07 00:13:50 +08:00
ThearchyHelios
a45ca28c6b
M2 片段接口的按需裁判说法照实写:正式运行的报告没开结论句裁判时,on_demand 不再说「已在报告撰写节点内完成裁判」,改说这份报告没有开启结论句裁判;开了裁判却因报告没通过核对而没判的也照实说;不是结论句的(标题、连接性文字)先答 not_a_claim;按需裁判接口对正式运行回 409 时说同一句话
...
验收里正式运行(claims: off)的片段接口对结论句、标题都答「已在节点内完成裁判」,节点里其实没判过。现在按文档里有没有当场裁判的摘要(mode inline)和写作时的结论句策略认,片段接口和 POST …/evidence/judge 共用 _formal_message。
2026-10-07 00:03:58 +08:00
ThearchyHelios
df6b0dd3ae
M4:触发历史的翻页游标写成 Z 结尾,照原样拼进查询串也能翻页
...
next_before 原来是「2026-10-06T14:37:03.376320+00:00」,照接口说明「原样传回」拼进地址时「+」被查询串解成空格,
回 422「翻页位置需要是接口返回的 next_before」。界面用 URLSearchParams 编码不受影响,照说明写脚本、做集成的会撞上。
现在游标是 UTC 的 Z 结尾、精确到微秒(和运行列表的游标一个写法,放进地址不用编码);解析时 Z、+00:00、被解成空格
的「 00:00」(老的游标照原样拼进地址时就是这样)都认,不是时间的照旧回 422。check-schedules 的假接口照服务端用记录
时间作游标,另加一节:老服务端给 +00:00 的游标时,页面编码成 %2B 传回、第二页接得上、不重复。
2026-10-07 00:02:15 +08:00
ThearchyHelios
e410d2a6a7
M4:单个工作流接口的 run_count 和列表接口按同一个函数算
...
验收时 GET /api/workflows/{id} 的 run_count 恒为 0,同一时刻列表接口里同一个工作流是 2 次、4 次:只有列表接口按
Run.workflow_id 计数,详情、保存(PATCH)、恢复旧版、新建、复制直接返回数据库对象,落在 WorkflowOut 的默认值 0 上。
计数抽成 _run_counts,列表和返回单个工作流的接口(_workflow_out)都走它,次数一致;新建、复制出来的工作流照实是 0。
2026-10-06 23:56:31 +08:00
ThearchyHelios
b4edcadc88
合入期 5 前置修复 L3:记录页的工件列表把双盲复算对照、反方审稿记录、质询回答归到「核查记录」一组,窄屏下说明换到第二行、序号不被截掉;运行对比的默认基准接口带上 previous,运行详情的对比入口在基准不是紧挨着的上一次时写明「与上一次成功的运行对比」,和触发历史一致
2026-10-06 22:19:25 +08:00
ThearchyHelios
7255ae98a5
模型接入报错收尾(第 1 轮复核,后端):交给设置的核查、裁判落到演示模型照实说;给不出修复时说卡在哪里;接入名恰好是模型名那句按这一处检查器里有哪几栏写;修复规划只重算被改的节点;助手栏那一格另给一份说法;几处措辞对齐
...
- 「不指定接入」交给设置(核查模型、裁判模型)时:启用的接入全是演示类,设置这一级不管写的是什么,执行时落到的都是
演示模型,说明照实带上「(演示用,不调用真实模型)」、候选带 demo 标记;一个启用的接入都没有时不算落得稳(同别处
「换成内置演示模型」不算)。以前 land() 在判演示之前就把交给设置的一处当成落稳返回了;
- 检查器里没有下拉框、发布前检查又给不出修复时,提示末尾补「无法改用其他接入:」加第一处落不稳的地方(Landing.why,
比如「成员「研究员」指定的模型「小模型」所属的模型接入「旧接入」已停用」),不再只剩「核对名称」让人去设置里找一个
找不到的名字;
- 点名的接入名恰好是某个启用接入的模型:画布、发布前检查按这一处在检查器里有哪几栏写(provider_refs._model_note)——
模型调用一类在节点的「模型」中选择它,接入在发布前检查里改用这个接入或选择「不指定接入」(修复里有哪项说哪项);
协作成员、全图默认只说可在发布前检查里改用;核查节点、报告自己的结论句裁判两栏都在,照设置页写这两栏的叫法。
不再叫人去一个没有的「接入」栏留空。运行时报错不分节点类型,「填写」改为「选择它」;
- 修复候选修完以后落到演示类接入的带 demo 标记,发布弹窗据此在选项名旁加醒目的标签;
- 性能:改一个节点的配置只影响它自己取模型的那几处,修复规划(autofix._ProviderPlan)每试一个候选只重算这个节点
(provider_refs.node_uses),不再深拷贝、重算整张图;问题提示只问给不给得出(provider_fixable,找到第一个落得稳的
就停);接入问题的引用整张图只算一遍。60 个节点都点名同一个停用接入时,画布校验里这一部分约 0.35 秒降到约 0.002 秒,
发布前检查约 0.72 秒降到约 0.01 秒,一次应用 30 条修复约 2.7 秒降到约 0.09 秒;
- 助手:GET /api/copilot/model 另给 panel_error(写在助手栏「助手使用的模型」那一格下面,去向写「上方」,不把人指回这个
下拉框本身);接入名恰好是模型名时并成一句,不再两次提「助手使用的模型」;PUT /api/settings 里助手那一项的 422 用
助手报错那一句(那里只有一个选模型的下拉框,没有「换一个接入」的地方);
- 裁判设置的格式检查写「留空表示跟随助手的模型」,同设置页空选项(engine/judge.py 一行,同核查那条的改法);「交给助手」
后只剩接入问题时写「助手无法处理」,有修复时另起半句「也可在各条问题下方选择改用的模型接入」。
测试:test_provider_ref_wording 加演示落在设置上、demo 标记、给不出修复时卡在哪里(含一个启用接入都没有)、各处的
接入名恰好是模型名、助手栏那一格的说法、助手那一项的 422、裁判格式检查、规划开销随节点数线性增长(数试算时算了多少处
取模型的地方);其余几个文件跟上新说法。新加的核心用例都做过去掉实现、测试变红的验证。
2026-10-06 19:43:44 +08:00
ThearchyHelios
4673e51bb8
模型接入报错的说法与修复候选收尾(后端):修复规划只否决这次改动造成的失败、问题只认自己那一处的修复、没有修复时提示不指到发布前检查、落到演示类接入照实说;各处说法对齐
...
修复规划(autofix.provider_choice,原 _plan_provider 的主体,provider_refs 也用它判断给不给得出修复):
- 改动波及的一处,要是点名的接入没变、而那个接入本来就不存在或已停用,它落不稳不是这次改动造成的,不再拿它否决候选。
以前两处互相牵连(节点点名的接入写错、模型取全图默认里停用接入的模型)时两条问题都没有修复,规划器自己卡住;
- 点名的模型接入一处一条修复,annotate 只认(编号、节点、字段)都对得上的那一条,认不出就是没有,不再退到同节点、
同编号别处的修复(以前全图默认那条的 fix 会指到某个节点的修复上);
- 一个候选都落不稳时,问题提示不再写「或在「发布前检查」中改用其他接入」,只说去设置里核对、启用;
- 修完以后落到演示类接入(kind 为 mock)时,「不指定接入」的说明写明「演示用,不调用真实模型」,和「改用演示接入」
那一项一致——K1 要防的就是悄悄换成演示模型。
说法:
- 双盲复算、反方审稿的问题写「……的「盲算模型 · 接入」指定的模型接入」,不说「盲算模型指定的接入」(修复标题仍按角色说);
- 点名的接入名恰好是某个启用接入的模型时,运行时报错、画布问题、保存设置的 422、助手的报错都补一句这是哪个接入的
模型、怎么用它(factory.model_note;设置页写那一组模型、接入两栏的叫法),免得照「启用它」去启用那条旧接入;
- 保存设置 422:下拉框选的写「指定的」,不写「填写的」;去掉和设置页空选项对不上的留空半句;助手那一项叫「助手使用的
模型」;核查的格式检查写「留空表示跟随证据裁判模型」,同设置页;
- 「交给助手」后只剩接入问题时的说明:一句一个意思、不再带冒号(界面上前面已有「助手:」),「核对名称」有宾语,不说
「节点」;有一条带修复时才指到各条问题的修复;
- 助手的模型取不到时,提示指到真正能改的地方:「编排」页助手栏的「助手使用的模型」(设置页没有这一项);
- 节点点名了接入、没写模型时校验说「将使用接入「X」的默认模型」(编号 model.unset);X 本身不存在或已停用时画布校验、
发布一类都去掉这一条,只留接入那条,不再一条说照常执行、一条说会失败。
2026-10-06 17:29:18 +08:00
ThearchyHelios
50f15b40c4
合入期 5 前置修复 K1:点名的模型接入不存在或已停用时照实报错,不再悄悄换成演示模型——各条用到模型的路径照实失败或记为核查不可用;保存设置时 422、画布校验给警告、发布与发布前检查挡住并给修复候选(不指定模型、改用启用的接入),只写模型而提供它的接入已停用也查得出
2026-10-06 16:55:27 +08:00
ThearchyHelios
5c6820f602
运行对比的默认基准(GET /api/runs/{id}/compare/base)带上 previous:基准是不是紧挨着的上一次,取 pick_base 现成算好的那个值,和定时任务自动对比记下的 previous 同一个语义
...
运行详情「更多」里的入口要按它定叫法:上一次失败、取消、还没结束时,基准是再往前成功的那一次,菜单得和触发历史一样写「与上一次成功的运行对比」,不能一律写「与上一次对比」。测试钉住:同一定时任务、退回同一工作流两种范围里,失败、取消、还没结束、没封存的都算隔着,别的运行类别、别的定时任务、比这次晚发起的不算;上一次失败时运行详情和触发历史拿到同一个基准、同一个 previous;中间那次删掉之后运行详情按现在的记录算成紧挨着的上一次
2026-10-06 16:42:29 +08:00
ThearchyHelios
0a690a599b
发布前修复点名的模型接入:按执行时的取法算修完落到哪里,只写了模型而接入已停用的也拦下
...
- 「不指定接入」以前只去掉接入、留下同一处写着的模型,复核又只查点名的接入:按模型名落回停用的接入,或者成员跟随节点、节点跟随全图默认,拿别家的接入去调这个模型。检查、发布都通过,正式运行在那一处照样失败
- 现在每个候选(不指定、改用某个启用的接入)先在副本上改,按执行器的取法(成员先看自己、再看节点、再看全图默认;节点看全图默认;都没写按模型名找;核查和裁判整组交给设置)算出改动波及的每一处用哪个接入、哪个模型。落到的接入不提供那一处的模型、按模型名落到停用接入或认不出的模型、落到内置演示模型的,连同一级写着的模型一并去掉再算,还落不稳的候选不给;候选说明写清执行时改用哪里、模型去没去掉、换上的接入实际用哪个模型
- 门禁把哪一级都没写接入、只写了模型而提供它的接入已停用的那一处也记成 provider.disabled(落在写模型的字段,原因和运行时同一句):复核拒得掉这类修复,检查器里只能选模型的节点发布前也查得出来;这一处配「不指定模型」或改用一个启用接入的修复
- 按模型名找接入、没写时退回哪个接入抽成 factory.provider_for_model、fallback_provider,运行时和门禁共用一份
- 问题面板、修复预览写得出「模型」「成员「x」的模型」;check-publish 的伪造门禁跟上新的候选,补只写模型的一段
- 测试:复核发现的几种形状逐一钉住(含发布前检查修好、保存、发布后正式运行成功的端到端一条);依赖旧做法的两条测试改成新的正确行为
2026-10-06 16:31:06 +08:00
ThearchyHelios
4314a7fc44
合入期 5 前置修复 K2:核查与裁判模型的输出额度提到 16384,服务方嫌大时退回 4096(和助手共用 providers/budget.py);每次调用认截断,因推理占满额度没交出结果时照实说(verify_truncated、judge_truncated),不再说成盲算没查到、没按结构交结果
2026-10-06 16:26:37 +08:00
ThearchyHelios
0a875fd3af
合入期 4 整合 J4:质询回答工件在记录页有名字和说明;问答串在审批列表取失败时不再漏条目;运行对比的默认基准与定时任务自动对比用同一条规则(同一任务、同一工作流、比这次先发起的上一次成功并封存的运行),触发历史在基准不是紧挨着的上一次时写明「与上一次成功的运行对比」
2026-10-06 16:23:40 +08:00
ThearchyHelios
ed888d59df
合入期 4 整合 J3:出具横幅按「核查未通过 / 核查未完成 / 校验未全部完成」分组;审批卡把运行类别交给反方审稿概况;证据接口的核查类型契约挪进 types.ts;反方审稿加单句模式、证据面板不再谈出具;证据接口带上句子的反方判断映射,正文给被审过的句子挂句末标记;质询图标平时对比度达标
2026-10-06 16:23:33 +08:00
ThearchyHelios
3c51c40e9d
点名的模型接入:发布前检查给每一处配修复,提示指到界面上真能改的地方,复核发现的几处漏查、误查补齐
...
多数节点(模型调用、Agent、报告撰写、多 Agent 协作、条件分支、结构校验、知识检索)、协作成员和全图默认的接入在检查器里没有下拉框,以前点名的接入坏了只能去设置里建一个同名接入。现在门禁接受接入表(governance.lint_for_publish 的 providers,接口层读好传进来,同数据目录 SQL 检查器),点名接入的问题成了门禁的一部分,自动修复给每一处一条要人选的修复:改用一个启用的接入,或不指定接入;选的接入不提供这一处写着的模型时模型一并去掉。一处一条(修复 id 带字段,复核只认那个字段),协作节点自己的接入和成员的接入各修各的。校验和发布检查的提示按位置写:有下拉框的说「在节点中换一个接入」,别处说「在发布前检查中改用其他接入」;剩下的只有接入问题时交给助手的说明也改成指向这些修复。
复核发现一并修:核查节点自己的开关关着、结构校验不许重试时不再查(执行时根本不取模型,以前会挡住发布);报告没写裁判配置时查全图默认里的那一份(以前放行,正式运行却全部未裁判);接入名不是字符串时查助手模型的接口不再 500,设置接口对门控、助手两组的这类值回 422 带字段;助手、表格导入、数据目录起草用的模型点名的接入不存在或已停用时照实说是哪个接入、去哪里改(以前说「尚未配置完成」,停用接入的下一步丢了),删掉两处已走不到的分支。
测试补齐:结构校验让模型修复、知识检索让模型重排、按需裁判各路径的不存在与已停用,助手、定时正式运行、裁判的两种情况,反方审稿节点上点名的接入;修复的候选、应用、拒收和图级默认。
2026-10-06 15:14:26 +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
1bee9b5100
触发历史不再给基准已过时的自动对比;对比页找不到默认基准时标题不再和「可在上方选择」打架,换基准的下拉和基准卡写明失败、取消的运行
...
- 中间失败的那次事后被接着运行成功之后,第 3 周存着的那份对比(比的是第 1 周,previous 为假)和运行详情「与上一次
对比」的默认基准(现在是第 2 周)又对不上,两处却都写「上一次成功的运行」。auto_compare.outdated 对基准当时就不是
紧挨着的上一次的那几份按 pick_base 现挑一遍,基准变了的算过时;api/schedules._fire_outs 对过时的给 null(不给链接、
不给旧计数),两个同名入口比的始终是同一对运行。基准没变的照旧给:中间那次还没结束、后来失败、被删掉都一样。紧挨着
的上一次不会过时(两次之间插不进新的运行),不核
- test_base_follows_launch_order_not_finish_time 补上:接着运行完之后第 3 周的触发记录不再带对比、任务列表的 last_fire
同样不带、运行详情的默认基准是第 2 周;另加一条基准仍是挑出来的那一次时照旧给出
- 对比页找不到默认基准:标题由「未找到可作为基准的运行」改为「没有默认基准」——失败、取消但封存了的运行不当默认基准,
却照样能在上方手动选;服务端的原因改成「没有找到上一次成功的运行:需要同一工作流、同一运行类别里比这次先发起、成功
结束并已封存的运行」,运行详情弹出的提示单独读也说得清
- 换基准的下拉给失败、已取消的运行写上状态,基准卡也标出来;下拉说明补一句默认基准只取成功结束的运行
- 运行详情「更多」的菜单项点之前不知道基准是哪一次,基准不是紧挨着的上一次时仍叫「与上一次对比」,和触发历史的叫法
不同:注释照实写明,留作后续
2026-10-06 13:33:40 +08:00
ThearchyHelios
cb3f20d6df
保存设置、画布校验、发布时就查出点名了不存在或已停用的模型接入
...
运行时点名的接入不存在或已停用现在照实报错,这里把问题提前到配置的时候:
- PUT /api/settings:门控模型、证据裁判、核查模型、助手这几项引用接入的字段写了不存在或已停用的接入
回 422 {detail, code: settings_provider_invalid, field: 组.键},说明写设置页上的叫法、和运行时报的
原因提示同一句;一组出错整次不落库,留空照旧表示沿用上一级。只查这次改了的值:写好之后接入才被删、
停用的,不挡这次保存同组别的项(设置页标着不存在,运行时照实报错),同设置页只校验改过的做法。
- 画布校验给警告,发布、发布前检查、自动修复的复核给错误挡住发布,问题落在节点和字段上(provider、
agents[i].provider、judge.provider,全图默认记 defaults.provider),编号 provider.missing /
provider.disabled。只查执行时真会取模型的那几处:分支让模型分类、校验让模型修复、检索让模型重排时
才算,报告交给模型裁判时才查裁判的接入,有节点会取全图默认时才查默认。判断在 engine/provider_refs.py,
接入表由接口这一层读出来交给它(门禁本身不查库,同 SQL 检查器)。自动修复后只剩接入问题、人又要
交给助手时说清助手处理不了。
test_verify_settings 的整组往返原来写了一个不存在的接入 house,改成先建一个演示类的接入。
2026-10-06 13:04:50 +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
6a53a76694
各条用到模型的路径照实报出接入不存在或已停用,查助手模型的接口不再 500
...
逐条核对 get_chat_model / resolve_provider 的调用方:模型调用、Agent、报告撰写节点按 NodeError 失败,
双盲复算记无法复算、反方审稿记未能反查、审批质询回答失败、结论句裁判记未裁判,原因都是「核查模型
不可用(…)」「裁判模型不可用(…)」这类整句;助手生成报 400,门控模型转人工审批,定时任务发起的
正式运行失败、通知照常推送。这些调用方原本就接了 ProviderNotConfigured,测试逐条钉住:产出、事件、
llm.end 里都不出现 mock-fast。
GET /api/copilot/model 原来直接调 resolve_provider 不接异常:存的接入不存在(现在会抛)、或只存了
模型名而它的接入已停用(以前就会抛)时整个接口 500。现在照常返回,effective_* 为空,error 写明原因,
能用时 error 为 None。
2026-10-06 12:52:54 +08:00
ThearchyHelios
4dd40ed201
输出额度的通用逻辑挪到 providers/budget.py:认截断(finish_reason=length、stop_reason=max_tokens、openai 的 LengthFinishReasonError)、认服务方嫌额度太大(400/422 且报错提到 max_tokens 一类)、截断那次的用量、给人看的「某某模型的输出达到上限(N token)被截断」,以及退回小额度的 BudgetFallback
...
BudgetFallback 在助手原来的做法上补齐核查和裁判要用的:非流式 ainvoke 也认;bind_tools、with_structured_output 包出来的和原来的共用同一个开关,另一份配置建的模型(核查收尾时关掉思考的那个)经 shared_with 也共用,工具循环里退回过,收尾那次直接用小的;小额度的模型可以要退回时才建,平常一个都不多建。只在还没吐出任何东西时重来,和原来一样。
助手改为引用它,_cut_off、_BudgetFallback、_BUDGET_WORDS 留着老名字,行为不变,助手和配方助手的测试照样通过。
2026-10-06 12:51:36 +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
69b70eceb3
证据图的每份报告带上被反方审过的句子 → 判断(challenge_verdicts):正文据此给被审句子挂句末标记,不逐句请求片段接口;和片段接口的 unit.challenge 共用同一个读审稿的迭代(_reviews),每句取最后跑完、审到了它的那次审稿,审稿记录丢了按产出里列的那几句,节点报错按审完时的日志;一句都没审的报告没有这个键
2026-10-06 12:02:03 +08:00
ThearchyHelios
544d44bdc2
运行对比的默认基准和定时任务的自动对比共用一个挑法:失败、取消的不当基准,按发起先后取上一次成功的运行
...
运行详情「更多」里的「与上一次对比」原先走 default_base:任何终态都算、按结束时间排,上一次失败时拿失败的那次当基准;
触发历史里同名的入口用的是自动对比的 _previous(同一定时任务里成功结束并封存的最近一次、按发起先后)。两处拿到的基准
不同,计数也对不上。
- api/compare.py 新增 pick_base:比这次先发起的运行里成功结束并封存的最近一次,同时给出是不是紧挨着的上一次。定时任务
发起的先找同一定时任务,没有再退回同一工作流、同一运行类别(同样只挑成功的、按发起先后);schedule_only 时不退
- default_base 与自动对比(scheduler/auto_compare.py,原 _previous 删掉)都调它;找不到基准的说明改成「上一次成功的运行」
- 测试:上一次失败、取消时默认基准跳过它们,和自动对比挑的是同一次;按发起先后而非结束时间(含停在审批上的这次);
之前没有成功的运行时回 404
2026-10-06 11:56:31 +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
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
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
f8ac8dc1d6
定时任务自动对比收尾:基准那一次不在终态或被删时不给对比、对比工件读不出来时触发历史照常打开;检查脚本按实际底色量对比度
...
- 触发历史的 compare:以前只看这一次的运行在不在终态。基准那一次被强制删除、失败后被继续执行时,对比页比不了,
「对比上一次」链过去只会报错——基准一侧同样要在终态,否则给 null
- 对比工件读不出来(权限、磁盘出错)时记一条警告、给 null:以前 OSError 直接抛出,整页触发历史回 500。被改过
(内容与哈希不符)的以前就给 null,这次补上用例
- check-schedules:页头的定时任务链接、触发历史的「对比上一次」改成量 WCAG 对比度(≥ 4.5),底色顺着祖先叠到
不透明为止。以前比的是「字色不等于页头的底色」,页头本身透明,那样比永远成立;深色也补上同样的检查。另加一项
署名的立即运行配长名字:署名照写、链接截断、页头不横向溢出
2026-10-06 07:43:01 +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
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
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
e9cf74748f
合入期 3 反方审稿(后端):报告里的关键结论各派只读 agent 主动找反例,给出经受住、被削弱、被推翻、无法判断和有出处的理由;被推翻的计入出具缺口;审批卡附反方审稿概况
...
# Conflicts:
# backend/tests/test_issuance_upstream_gaps.py
2026-10-05 18:08:39 +08:00