20 Commits

Author SHA1 Message Date
ThearchyHelios 9339facf9a 运行对比里的分析卡只认做完了的那次执行:analysis.end 先按卡记在这一次执行里,见到这张卡的 node.finished 才算数(新的 node.started 清掉上一次没做完的)。分析卡执行到一半失败时前几项已经发了 analysis.end,以前运行对比会把这次失败执行的判定当成结果列出来、也算进执行次数。测试:中途失败的那次不列、不算次数,失败后重来做完的按做完的那次对比 2026-10-21 15:50:15 +08:00
ThearchyHelios a81a0a66ac 合入 W1-d 说法核对:说法表与绑定、check / strict / off、出口独立复核与文档版本、分析范围、血缘口子、G3 2026-10-21 14:00:07 +08:00
ThearchyHelios 767b1ac07a 报告撰写节点加「分析说法核对」(analysis_claims:off / check / strict,缺省 check)和「分析范围」(analysis_scope:auto / off,缺省 auto),画布校验和执行时报同一句话(report.analysis_claims_invalid / analysis_scope_invalid),界面叫法进 labels,运行对比登记这两项。check:判断词没挂对分析结论、原因没有依据的句子交回写作者重写一次(不按最多重写次数反复),仍有的标在报告里、写一条日志 report_analysis_claims,不影响档位;strict:按最多重写次数重写,仍有的写进产出的 issuance_gaps(另记 analysis_gap);两种都不让节点失败(不挡生成);off 不核、写作规则和文档一字不变;升级前发起的运行照旧。写作者角色改成「挑重点、组织结构、说清变化;有分析结论时说清变化来自哪里;原因只按证据写」,写作规则按目录里有没有分析结论各加一段判断词规则,重写请求列出违规和修法;这次有分析结论、取值 auto 时每一稿文档都带系统写的 analysis_scope。产出和 report.checked 记下处置。几个测裁判、结论句策略、审计表的用例写作者那句「增长主要来自新客」没有拆解可挂,把分析说法核对关掉 2026-10-21 13:12:15 +08:00
ThearchyHelios e079e0ba88 分析能力入口(五):运行对比里两次运行的分析卡按节点和项的标识对齐(engine/compare.py 的 analyses,最小可用):按封存范围内每项一条的 analysis.end 认,循环里执行了几次的取最后一次(照实写进说明);每项列出两次的状态、判定、方向、判定语和结论工件,change 写 same / verdict(状态或判定变了)/ phrase(判定一样、判定语里的数变了)/ added / removed,不拆变化来源 2026-10-21 13:03:29 +08:00
ThearchyHelios 301bbd55f3 口径卡分母为 0 时算不出来就是空值,和「缺少输入」分开说;指标清单按格式渲染。助手节点手册讲口径卡的那段写明分母可能为 0 时写「… if 分母 else None」、不要写 else 0,附示例;画布校验加一条提醒 metrics.zero_for_undefined(按语法树认:条件表达式一边有除法、另一边是常量 0,两边对调、套在 round 里、嵌套的都认)。输入都齐、计算式自己交回空值的指标多记 undefined: true(状态仍是 missing_input,按状态认的地方和老运行不受影响),清单、写作目录、引用解析不了的原因、运行对比、证据面板都说「算不出来(这组输入下计算式没有值,比如分母为 0)」;推演把它当不带值的字段。指标清单({{ nodes.卡.text }})改用卡上渲染好的 rendered:比率 0.0007 显示成 0.07%、金额带千分位,和报告里 [[m:]] 一致;有值却显示不出来的照实说,不拼原值 2026-10-20 10:04:53 +08:00
ThearchyHelios aa051b0a28 运行对比里子工作流的口径卡按卡所在那一层找产出:组装推演用的 Sources 时带上是哪张卡,节点产出、跑完的时刻按 engine/lineage.in_scope 换成卡那一层的 id(同推演 api/whatif._sources、证据面板 _InputMasks._output)。以前子图里的卡取值链写的是子图里的 id(nodes.parse),对比拿父图里同名的节点当它的产出,容器输入认到父图那次查询上;加一条子图卡的真跑对比测试 2026-10-19 09:03:37 +08:00
ThearchyHelios 1f8250699c 口径卡来源支持节点改名映射 caliber_from.nodes(口径账本做法 4 ③)
为什么:组合式问数、对账、召回要把一份口径的取数节点拷进另一张图,同一张图里放两份口径时节点 id 会撞,拷过来的取数节点得改名(c1_fetch)。以前 caliber_from 只认同名的取数节点,改了名口径卡就取不到输入。

做了什么:
- metrics._pinned_caliber 认 caliber_from.nodes {原 id: 新 id}:按语法树把式子里 nodes.<原 id>(含 cell(nodes.X, …) 的第一个参数、nodes['X'])的根换成新 id 再算,字符串字面量里的字不动;指标集的 source 照记映射。映射形状不对节点失败并说清哪一处。
- 画布校验 _caliber_from_issues:映射的形状和运行时同一个判断(rename_problem),改名后的节点要在图里、在口径卡上游。
- 升版检查照常挡、照常记事件,事件带上 caliber_nodes;证据的 _caliber_source / _caliber_upgrade 照带映射。
- 运行对比按映射把式子换回那一版里的写法再比:同一份口径换了节点名不算口径变了。推演按卡上记的改名后的式子原样重算。
- 没写 nodes 的老图一字不差:式子不经 unparse、来源只有三项、升版事件没有新键(单独测)。

测试:tests/test_caliber_from_nodes.py(改写规则、运行时取值、证据链、推演、校验、升版检查、对比、老图不变)。
2026-10-16 16:20:25 +08:00
ThearchyHelios 5dba66c2b6 应用平台 BE-1 治理底座:身份三种模式(off 默认 / local / oidc)、会话与 CSRF、中间件写入身份、角色与组与审计、按权限矩阵挂路由级依赖、运行与工件的读权限和 user 角色遮罩、reset-admin 找回;能力登记(同步、治理与乐观锁、发起快照、发布版本、作证判定)、登记的端点与平台执行器(分环境、演练、幂等头、身份断言、端点快照作证)、密钥加密与掩码、MCP 的 SSRF 与认证头、写入能力只进调用工具节点、正式运行里只读免审批的能力直接执行、四条 action.* 发布检查(含统一复核后的修复) 2026-10-14 20:05:23 +08:00
ThearchyHelios 5f48f8727e 运行对比加固(收尾):区域等维度列设了遮罩时照样拿它核对两次引用的是不是同一批行,说明只写行号、不写值,挤出引用行段的和真的少了分得清,没挪的照常是数据变化;补单格反方向、归因维度按两边各自引用的行认、写入者改了配置时不严格拆分、并行支路查询四处守护用例 2026-10-05 16:41:59 +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 44e4597037 运行对比加固(第 2 轮):行段要把引用过的每个区域切在同一处——一边整个被引用、另一边只引用了一部分的,引用的行数没变少也说不清;只在一边有的区域那一边算整个被引用;引用的行不从第 1 行开始时还要是它同样的那几行;单格只看那一行是不是同一个区域
- 一个区域在一边整个被引用、另一边只引用了一部分(其余的行还在快照里):上一轮只在「有行在外面的那一边引用得少」时判说不清,南区这次多了一天、引用的行只盖住前两天(行数没变少,甚至更多)照样报成只数据变,归因和「真的只有这几天」的对照一字不差,反方向连正负号都反了;现在按切法比:两边都整个被引用,或者都只引用了它同样的那几行,才是同一组数
- 只在一边的快照里有的区域,没有它的那一边算整个被引用:北区这次新出现、三天只引用了两天,基准运行南区只引用了一天、这次南区没了,都说不清;新出现、没有了的区域整个被引用的照常是数据变化
- 引用的行不从第 1 行开始时,按「排在引用的行前面的行数、引用的行数」认引用的是它的哪几行:两边都只引用了东区一行,基准是它金额第二高的那天、这次是最高的那天,说不清,说明里写出两边排在前面的行数
- 单格(数组元素)只看引用的那一行两次是不是同一个区域,不套行段的切法:东区两天还是一天,第 1 行都是东区的第一天;第 1 行的东区真的没有了照常比
- 说明说引用的行外面有它的那一边,两边都有的说引用得少的那一边;几个区域切法都不同时说基准运行引用的行里先出现的那个
- 截断的快照仍按取回的行比(和引用整份结果一致,挤到截断点后面的行看不到,不做归因),写进文档
- 新测试:一边整个一边部分(这次多一天、这次引用得更多、反方向,各带真的只有这几天的对照,占比之和为 1)、切在同一处(两边都只引用南区第一天仍是数据变化)、行数不同两个方向的说明、几个区域都不同时说哪一个、排在前面的行数不同、只在一边有的区域(新出现、没有了)、两列维度一起认(含一边只有一个值的区域列)、单格只看那一行、挤出两行时的行号和行数(两个方向)、正好 3 行不写「等」、两个 Agent 都交得不同时点名画布上靠前的、单边遮罩时整体说明提到遮罩
2026-10-05 14:47:05 +08:00
ThearchyHelios 36848f0a1e 运行对比加固(第 1 轮):一个维度值占几行时按维度值数两边各引用了几行,有一部分挤出引用的行也判说不清;单格引用的快照读不出来时和行段一样说不清;补循环回边、写入者不知道时的措辞、严格拆分的范围、单边遮罩四处测试
- 区域 × 日期这类结果(日期不当维度),东区多了一天把南区的第二天挤到引用的行外面、仍在快照里:原来只记每个维度键在引用的行里外各自第一次出现的位置,两边都引用过南区就查不出,报成只数据变、南区少了一半;现在某个键在一边引用的行更少、那一边快照里引用的行外面还有它的行,判说不清,说明写「南区这次有 1 行在查询结果第 5 行,不在引用的行里」,两个方向都查;真的少了一天的照常是数据变化、占比之和为 1
- 遮罩列仍不当维度:只用没遮的列认,说明里只写没遮的列的值和行号;整个挪出去的维度值列出全部行号(最多 3 个,多的写「等」)
- 单格(数组元素)引用、一边快照读不出来时原来退回按行号认、报成只数据变,现在和行段一样说不清,说清是哪一边
- 新测试:循环回边上的节点算口径卡之前、写入者不知道时并行支路只说「节点」且不说「它的上游节点」、严格拆分不被口径卡自己和下游挡住、只有一边遮了区域列(两个方向)时说明、归因、整体说明里都不出现区域名
2026-10-05 13:14:41 +08:00
ThearchyHelios 36569e1fa4 运行对比复核修正(第 3 轮):行号相同的引用还要引用同一批维度值,记不出写入者时只看口径卡之前的节点,默认设置的登记按节点类型逐类核对
- Agent 两次引用的行号相同、都不是整份结果时,一边引用了的维度值(区域……)在另一边的快照里却没被引用(按区域排序多了北区、按金额取前 3 名名次变了),判为说不清,说明写出是哪个维度值、在第几行;不再把还在快照里的区域算成「数据没了」、给出远超 100% 的占比。另一边快照里真的没有了的照常是数据变化。数组字段里的单个元素同样核对。维度按两边整份结果认,遮罩列不拿来认,分不出维度的仍按行号认
- 两边都记不出写入者时,范围从整张图改为口径卡之前可能执行过的节点(它的上游加并行支路):口径卡自己、只在它下游的写周报写不了它读到的值,不再被点名成来源;并行支路上的节点不说成「上游」
- 「整份结果」统一按引用了哪几行判断,容器一支不再单列
- 默认设置登记表的核对测试改为按节点类型:从各执行器出发顺着用到的函数(含就地 import、回调、类)找 cfg 读法,在字面量元组上循环读的键名认得出,认不出的变量键名直接失败;核对节点模块里每个读配置的函数都走到了,登记了不读的也算错。据此补登记成果节点出具契约读的报告节点三项(evidence_from、metrics_from、entities)
- 补测试守住上一轮的几条规则:Agent 交的不同而代码节点的数没变是没变,只有这次运行的快照读不出来时说这次,默认设置同时改了结论句裁判时 Agent 只写模型,调不调模型由默认设置决定,报告节点在代码节点上游,改了几个节点时点名画布上靠前的
2026-10-05 12:28:38 +08:00
ThearchyHelios 3254744f6d 运行对比复核修正(第 2 轮):行段相同、一边是整份结果的引用不再算同一处,默认设置的变化只落到会读它的节点上,上游 Agent 交出的结果不同时不再说变化来自上游数据
- Agent 两次引用同一段行,一边是整份结果、一边不是(这次多了北区,没引用的西区还在快照里):判为无法比较,写明哪边引用了整份结果、另一边引用了哪几行、结果共几行;快照读不出来、核对不了是不是整份结果的同样不算同一处。以前按同一处算,西区被算成「数据没了」,占比超过 100%
- 图级默认设置的变化按「哪类节点运行时会读这一项」落到节点上(_CFG_KEYS,照各执行器经 NodeContext.cfg 读的配置项登记):结论句裁判、结论句的处理只有报告节点读,不再把 Agent 记成配置变了;条件分支让模型分类、结构校验让模型修复、知识检索用模型重排时也读默认模型,同样落到它们身上。新测试按执行器源码核对这张表,执行器新读了一项没登记就失败
- 代码、数据整形这类节点的上游有 Agent、模型调用、人工审批等节点,两次交出的产出不同(工件按内容寻址,按工件 id 比;产出没落成工件的核对不了):它交的数变了不再说变化来自上游数据,判为无法比较并点名是哪个节点
- 上游节点改了配置时说明里点名是哪个节点;默认设置那句拆短,写出跟着变的是哪几项(模型接入不写 provider)
- 补测试守住复核列出的未覆盖规则:容器运行输入还原不了、合并查询的输入追不下去、上游只有运行输入变了、审批默认设置、图里 SQL 只改格式(代码节点在下游)、跨节点先配字面量相同的、少了一次查询、只有一边落在快照上、查过库的写入节点改了配置、代码节点上游有节点改了配置、旧口径叶子的出处说不清时不拆、单格引用换了行;变异 99 处全部打红
2026-10-05 11:28:41 +08:00
ThearchyHelios d176ff77ff 运行对比复核修正(第 1 轮):输入的出处追到合并查询的上游、Agent 引用的列和行段,没出处的数、数据没变数却变了的不再报成数据变化
出处判定(每个指标的分类靠它):
- 合并查询:读合并结果的指标按别名一路追到喂它的每一份上游快照(嵌套的合并也追),上游 SQL 结构变了是 sql_changed,
  不拆、不归因;合并节点多接、少接了输入也算结构变化
- 图里写死的字面量改了('paid' 改成 'refunded'、系数、LIMIT):执行的 SQL 只差字面量,但图里的 SQL 改过,算模板变化;
  图里一字未改(定时运行代入的日期)才是参数。图里的 SQL 只改了空白、大小写的不算改过
- Agent 按出处交来的字段:还要引用同一列、同一行(段),两边都引用整份结果的不算换了;换了列、换了行段的说不清
  (incomparable),不再把没引用的区域算成「数据没了」去归因
- 模型、人直接交出的值(Agent 没按出处交、模型调用、人工审批……):值变了说不清是数据还是模型本身,判 incomparable;
  它自己查的库结构变了、配置变了照常标出
- 代码等确定性节点:上游的查询结果两次一模一样、交出的值却变了的,判 incomparable,不再说「变化来自上游数据」;
  上游只有运行输入变了的算参数
- 图级变化落到节点上:连线有增删的终点节点、默认设置改了且没有自行设置这几项的模型类节点,都算改了配置;
  「模板和取数的 SQL 都没有变化」只在整张图都没变时说
- 运行输入是列表、对象的,按还原出来的完整值比,长度不变、内容变了的是参数变化
- 同一节点按 SQL 配对时先配字面量也相同的:Agent 换了先后查东区、南区,两条各自配上自己,不再配成两条「只有参数不同」
- 一边记不出输入是哪个节点写的,说清是哪一边没记录(不再写出「None」)

口径与数值:
- 口径变了的指标,喂它的取数也变了、说不清的照样写进说明(只在一边才有的输入是改表达式带来的,不重复说);
  分类次序写进 compare() 的说明
- 千分位和不分组互换只影响显示,写进说明、不算口径变化;比率与否不同才算
- 升级前的口径卡没记小数位、显示格式:按那次运行图里的指标定义核对,定义也没有就不比,不再误报「小数位由 未设置 改为 1」
- 百分比:基准极小、这次很大时十进制量化放不下,退回浮点算,不再整个对比报 500
- 没设小数位的指标拆分:三个数按同一精度量化(最多 15 位有效数字),转成浮点交出去后两效应之和仍逐位等于总变化
- 维度归因标出用的是哪个输入、两边各自哪份快照(path、base_artifact、target_artifact)

接口:已经结束、只是没有封存清单的运行,409 说「没有封存清单,不能用于对比」,不再说「运行结束后才能对比」。

测试:补上复核指出的必测项(只一边对得上不给占比、只截断基准一侧、换了数据源、按旧口径小数位取整、写它的节点多查一次、
口径和 SQL 一起变不归因、小数位和比率变化、日期类型和常量列不当维度、合计行浮点误差、只改名称、结束过又接着运行的不当
基准),以及上面每一处修正的用例。32 处变异逐条打红验证,全部被测试抓到。
2026-10-05 10:20:29 +08:00
ThearchyHelios 63c54e1c20 运行对比:compare() 的说明里写全返回的形状,接口说明指过来时前端照着就能读
除接口约定的字段外,几处补充也写明:模板节点的 labels(配置项的中文叫法)、输入的 masked 和两边的快照 id、查询的
两边快照 id、differences 和 problem;归不了因时 rows 为空、total_delta 为空、原因在 note。
2026-10-05 09:00:09 +08:00
ThearchyHelios 1e90a5a502 运行对比:结果里不出现非数和无穷大,维度列的非数当文字配对
接口按 allow_nan=False 写 JSON,结果里混进一个 NaN 或 Infinity 就是 500。指标值、输入值、十进制相减原本就只出
有限的数;剩下两处补上:维度列里的非数(float NaN)写成文字再当键,度量加起来、占比算出来超出浮点范围的给空。
2026-10-05 08:58:18 +08:00
ThearchyHelios 467f9599fd 运行对比:补合并查询、循环里多次执行的配对测试,口径卡读不出来时的说法补上「的」
合并查询只记在节点台账里、SQL 另在 merge.end 里,快照文件不在了照样比得了 SQL;循环里同一个节点执行几次的按先后
一一配上,多出来的一次标「删除」。口径卡指标集读不出来、被改过时的说明改成「口径卡「X」的指标集与哈希不一致」。
2026-10-05 08:55:57 +08:00
ThearchyHelios c89aaba10c 运行对比:Agent 换了查询先后时按 SQL 配对,Agent 改了配置时按出处交来的字段不再报成数据变化
查询配对改成一轮比一轮宽:同一节点、同一工具里规范化 SQL 相同的先配上,剩下的再按「第几次」配,最后跨节点按
SQL 配。以前严格按第几次配,Agent 这次换了查询的先后,两条都被配成「结构变了」,没按出处交的字段跟着被判成
SQL 变了。

Agent 按出处交来的字段:SQL 没变而 Agent 自己的配置(提示词、工具)变了时,它可能换了取哪一格,归为模板变化
(sql_changed)并写明是哪个 Agent;调用工具节点的格子由口径卡的 cell() 定,不受影响。
2026-10-05 08:52:04 +08:00
ThearchyHelios 86e52192a9 运行对比后端(变化三分法):两次运行按指标拆清是数据变了、口径变了还是模板 / SQL 变了,数据变化按维度归因
GET /api/runs/{id}/compare/base 找默认基准:定时任务发起的先找同一定时任务更早结束的一次,否则同一工作流、
同一运行类别;只挑封存过的终态运行,找不到 404。GET /api/runs/{id}/compare?base= 对比两次运行:两次都要
已结束、封存且核对一致(照搬证据接口的封存判定),否则 409;不是同一个工作流、同一次运行 422。只读,不追加
事件、不落工件。

engine/compare.py 是纯函数:
- 查询按「节点 + 第几次 + 工具」配对,配不上再按规范化 SQL 配;normalize_sql 判 same / params_only /
  changed,结构变了的用 diff_facets 写出差在哪(时间范围排在最后);核查类查询不参与
- 口径卡同一节点按指标 id 配对,表达式、口径版本、小数位、单位、显示格式不同算口径变了
- 每个指标按 added/removed → 口径 → SQL 或上游配置 → 说不清 → 只参数 → 数据 的次序分类;输入落在快照上
  的直接比两边快照的 SQL,不落在快照上的看写它的节点和画布上游
- 口径变了时严格拆分:旧表达式配这次的输入用推演重算的还原和求值算 f_old(x_new),十进制精确相减,两效应之和
  逐位等于总变化;SQL 也变了、用到遮罩列、单位不同、旧叶子没记录的不拆并说明
- 维度归因按维度键配对两边的行、取变化最大的 10 个;度量之和等于输入的值(含合计行那一格)才给占比;截断、
  度量列遮罩照实写;遮罩列、日期列、每期都不同的列不当维度
2026-10-05 08:49:52 +08:00