Commit Graph

908 Commits

Author SHA1 Message Date
ThearchyHelios 94f028fcef 合入 nr6/a:认口径按答案引用的那几列投影后再判等价(判定仍只走现有的 match_template)、差异说明投影之后再说并认得 LEFT JOIN ON 里的日期条件、转抄口径卡指标的出处跨卡追到取数查询(对账、召回不再降档)、认证队列按规范形分组、问题聚类的类 id 由成员定、use_caliber 的协议写清 card 2026-10-17 12:28:04 +08:00
ThearchyHelios d4f1ba8dd4 给评测留一个按引用的列投影的入口(referenced_of),顺手折行、补模块说明
- ledger/match.referenced_of(sealed):这次运行封存的报告引用了哪条查询的哪几列,正好是 compare_queries 的 referenced。
  评测逐题比 SQL(eval/score.sql_match,另一组在改)传它,就和账本一样按引用的列投影,不必自己再拼一遍。compute 和它
  共用读指标集的那一段(_card_loader)。
- data/sql_semantics 模块说明的「几处共用这里」补上模板绑定、按引用的列投影、同一个形状三处。
- 本轮几处新代码折到 120 列以内(只换行,不改逻辑)。

测试:tests/test_ledger_projection.py 的整题等价那条另核 referenced_of 交回的就是被引用的那一列。
2026-10-17 12:22:48 +08:00
ThearchyHelios 8c2ff49b50 use_caliber 的协议写清 card 填什么,写错了交回的原因能一次改对
真实验收里模型第一次常把 card 写成自己起的 c1 被拒,之后才改对:协议示例写的是 "card":"口径卡节点 id",紧接着又说
「口径卡(节点 id 就是 c1)」,两个 id 混在一起。

- api/copilot_context.USE_CALIBER_PROMPT:示例写 "card":"card";说清 workflow_id、version、card 原样照抄,只改 id、metrics、
  inputs;card 是那一版工作流图里口径卡的节点 id(查看结果的写法里写好了),id 是这次选用自己起的名字、生成的口径卡用它当
  节点 id;add_edge c1 → report 里的 c1 是自己起的 id。
- look/calibers.DETAIL_COMPOSE_PROMPT:同样写明 card 原样照抄、id 自己起。
- ledger/compose:card 写错时说清 card 要填节点 id、可填的有哪几个(「节点 id」(口径卡「名字」)),写成了自己起的 id 的
  另说一句「「c1」是你给这次选用起的 id,不是口径卡的节点 id」;几张卡要选时同样列节点 id。校验不放宽。

测试:tests/test_ledger_compose.py 新增两条(协议写清两个 id;card 写成自己的 id 被拒、原因说清该写什么,照着改成节点
id 就过)。改回原来的文字再跑,两条失败。
2026-10-17 12:17:21 +08:00
ThearchyHelios 1b31c49a00 问题聚类的类 id 由成员定,「不是口径」按成员记
类的 id 以前按种子问题的原文算:种子是一类里最新的那一句,时间相同的几句读出来先后不定、来了一句新问法种子就换了,
两次读取 id 就变,认证队列里点过的「不是口径」随之失效。

- app/chat/questions:Question.key 是稳定的 id(问数据的那一轮 turn:…、别的探索运行 run:…);QuestionCluster.id 是成员的
  id 排好之后取的哈希,同一批问题两次读取一样;recent_questions 同一时刻问的几句按 id 排出先后,不靠库里读出来的先后。
- ledger/certify:问题聚类那一项的 id 用类的 id;「不是口径」时服务端按同一批问题重新聚一次,记下这一类现在的成员(不收
  客户端传的成员,找不到、取向量出错就只记 id);之后这一类过半的成员是某一次记下的,就照样不进队——来了几句新问法 id
  会变,按成员认不失效。以前按种子原文算的 id 记的照样认;记的成员读不懂的照实忽略。
- api/ledger:dismiss 把当前身份交给 certify(重新聚类要按这个人读得到的问题)。

测试:tests/test_ledger_certify.py 新增三条——同一批问题换个先后读,种子不同、类的 id 一样;点过「不是口径」之后换个说法
再问一句,成员变了照样不进队,读不懂的老记录不报错也不藏;按旧的种子原文 id 记的照样生效。把 id 改回按种子原文、把按
成员认去掉再跑,各自的用例失败。
2026-10-17 12:15:07 +08:00
ThearchyHelios 72d9d2770c 认证队列的确定性重复按规范形分组:条件换序、AND 两边换位的进同一组
以前按 normalize_sql 的规范文本分组,WHERE 的条件照原文的先后,同一个形状换了条件顺序就拆成两组,凑不够门槛进不了队。

- sql_semantics.sql_shape:在判等价同一套不认列的规范形式(_light)上把字面量抹成只看类型(字还是数)的占位,再把交换律
  成立的地方按抹掉之后的写法重排——AND / OR 的各项、IN 列表、= / <> / + / * 的两边、比大小的两边(换边时大于小于跟着
  换);抹掉之后一样的几项按原值排,同一组里字面量的位置对得上。不另写解析器。认不出的(解析不了、sqlglot 会读错的写法、
  字面量对不回 normalize_sql 的)为 None,照旧按规范文本分组(只会分得细)。positions 把规范形里的字面量对回 normalize_sql
  的位置,固化成模板时用。
- ledger/certify:Shape 加 key / canonical / positions;队列按(数据源、规范形)分组,跨轮变了的位置按规范形对齐,再换回
  代表那条的位置;固化时同组的别的运行也按规范形认、按同样的对齐认参数。这一项的 id 按规范形算;以前按规范文本记的
  「不是口径」照样认(组里任何一条的规范文本对得上就算)。

测试:tests/test_ledger_certify.py 新增四条——三种换序写法同一个形状、字面量位置对得上;七种真不同(换列、OR、少条件、
换运算符、数对字、IN 列表、换聚合)不是同一个形状;真跑三轮换序的问数据进同一组、多筛一个地区的不进,固化出两个日期
参数;按旧 id 记的「不是口径」照样生效。把分组改回按文本再跑,换序那条失败。
2026-10-17 12:09:58 +08:00
ThearchyHelios c3123e3818 转抄口径卡指标的出处跨卡往下追,对账、召回运行按追到底的结果判档
对账卡的「口径」、召回卡的「旧版 / 新版」写成 nodes.<口径卡>.metrics[i].value,出处停在「来自口径卡指标」,对账运行、
召回运行一律降档出具(「输入没追到原始数据」);口径卡自己的指标明明追得到取数查询。

- engine/lineage:metric_copy 认出转抄一个指标的值的写法;traced() 对 via=metric 的输入看 upstream.traced;
  MAX_COPY_DEPTH = 8。
- engine/nodes/metrics:转抄的输入记 upstream {metric, artifact, depth, traced}——那张卡的指标集落了工件、那个指标的输入
  都追到了原始数据(它自己转抄的已经一层层追过,记在它的输入上)、层数没超上限才算追到;超了就算没追到(防环:循环里
  抄自己上一轮的卡每一轮多一层)。那个指标不完整、所依据的查询没通过 SQL 检查的,转抄出来的同样不完整、存疑,出具照样
  降档:信任按追到底的结果给,不多给。
- api/evidence:转抄的输入后面接一步 upstream(那张卡的那个指标:值、原式、代入式、它的输入、追没追到,取值按同一套遮罩),
  转抄的转抄接着追(同一个指标只接一次、最多 8 层),它的输入落在查询快照上的照常给查询步骤;出处链里遮着的列把这几步
  的输入也算上。reconcile.py、recall.py 生成的式子不用改。
- 前端证据面板:新的一节「转抄的口径卡指标」,输入来源里转抄的那一项写清追没追到、点一下跳到那一步,那一步的输入点一下
  跳到口径的取数查询(文案进 lib/terms.ts)。check-ledger 加一段:对账结果里点「按口径」的数,一路点到口径的取数查询。

测试:tests/test_metric_copy_lineage.py(转抄、转抄的转抄完整出具;转抄没追到的照样停在那张卡;上游不完整的转抄也不完整;
层数上限;真跑对账、召回都完整出具,出处链接上口径卡那一步、给出口径的取数查询)。去掉 upstream 再跑,5 条失败。
2026-10-17 12:05:12 +08:00
ThearchyHelios 12439b5305 差异说明投影之后再说;日期条件写在 LEFT JOIN 的 ON 里的说清楚
选择的列不同时,差异说明整段退回「两条 SQL 的写法不同,未能归纳成具体差异」(真实验收 E2 的兜底比例 45%):只差在选择
列表上时一条具体说法都没有;多选的列里有 sqlglot 不认识的函数(SQLite 的 printf 这类)时整段不算简单形状,WHERE 里
真实的差别也不写。

- ledger/match:按引用的列投影过、仍没证明的候选,差在哪用投影之后那次比较的结果;答案多选了列的,在最前面写一句
  「这次多查了 N 列,不影响这个数」(aspect=projection),然后照常说条件、时间、聚合上的不同。E1 的差异类型不数这一句。
- sql_semantics 的 _Explainer._left_on_times:两边来源一样、只差在一个 LEFT JOIN 的 ON 里的时间条件时,说「这次用 LEFT
  JOIN 关联 orders 表时只关联 … 的行,口径没有这个条件」「…时对 paid_at 的条件是 …,口径是 …」「…时按 paid_at 筛时间,
  口径按 created_at」。说得准才说:差的每个条件都是只涉及可空一侧那张表的时间条件、那张表只出现在结果里(WHERE、
  HAVING、别的连接没用到,SELECT 列表用到了)、同一列的按取值算过确实不同、单边的不是恒为真;套着日期函数认不准的、
  反连接、结果里没用到可空一侧的、不是时间条件的照实兜底。aspect 写 join(说的是关联条件),双盲复算不会把它当业务日期
  写进数据目录。只改说明,判等价不变。

测试:tests/test_ledger_projection.py(没证明时先说多查了几列、再说少了 status 条件,不再兜底)、
tests/test_sql_left_on_times.py(四种说得清的、在虚构库上结果确实不同;四种说不清的照实兜底;判等价的结论不变)。
去掉这两处改动再跑,各自的用例失败(2 条、8 条)。
2026-10-17 11:49:31 +08:00
ThearchyHelios 2a4086ab73 认口径按答案引用的那几列比:整条比不等价时先投影再交现有的绑定和判等价
真实助手的 SQL 总会多选几列(订单数、日期常量、MIN / MAX、COALESCE),报告只引用其中一列,口径的取数也只选它的指标要的
那几列。以前整条比,「上周的销售额是多少」3/3 只标相关口径、从不自动出具。

做法:sql_semantics 新增 project_select / project_template / output_names。按方言切词、按括号深度认出最外层 SELECT
列表每一项在原文里的起止,只把留下的几项原样拼回去(选择列表前后一字不动,保真守卫照样看得到原文),拼完重新解析、
语法树要和「原树换成留下的几项」一模一样。只在确定去掉不影响时投影,否则照实给原因、照旧整条比:DISTINCT / DISTINCT ON、
出现在 GROUP BY 里、被 ORDER BY / HAVING / QUALIFY / 窗口用到(按别名、同样的写法、按位置)、有 LIMIT / OFFSET 又不是
只出一行的聚合、集合运算、*、可能改变行数或不认识的函数、去掉仅有的聚合、留下按任意一行取值的列、调换先后时引用别的
选择项的名字,一律不去。

ledger/match:整条比不等价时,答案一侧按报告引用了这条查询的哪几列(labels.referenced_columns)投影,口径一侧按口径卡
上每个指标读了这个取数节点的哪几列(labels.card_reads)投影,投影后照样交 match_template(不另开给信任的路)。被引用的
列两边怎么对上写进模块说明:答案按列名在快照结果列里找位置、口径按 cell() 里的列名在输出名里找位置,投影后按位置配对,
答案留下两三列时另试调换先后,每份口径取数最多试 12 种。证明了的候选记 projection;没投影可试的逐对和以前一字不差。
算法版本升到 3;E1 另数 proven_projected;对账按投影后留下的列配对(不用人选)。

测试:tests/test_sql_projection.py(该去的、不该去的各一组,语料里 305 种投影在虚构库上执行守门)、
tests/test_ledger_projection.py(多选一列 / 多几个聚合 / 日期常量列能证明;多一个分组列、DISTINCT、按别的列排序加
LIMIT、HAVING 用到多出来的聚合仍然证明不了且和不投影时一字不差;口径一侧投影、调换先后;真跑一次整题等价;对账配对)。
去掉投影再跑,7 条失败。
2026-10-17 11:47:26 +08:00
ThearchyHelios fdd889b73a 合入最终验收(免模型部分)查出的 12 项修正:取值观察的「量跌」「缺天」不再拿今天这个不完整的日子比、按日行数只数到观察当天、「今天」统一按服务端所在时区;同一列条件被改写时差异说明说清两边的写法(判等价不变);用量计量记对模型名;探查范围外的表照实说「在探查范围外」;对被驳回的运行 resume 说「被驳回」;固化口径草稿用传入的名字、报告指令不写死日期、指标名取中文名、frozen_into 去重;剖析对话框可以直接发起取值观察,定时维护挑不出表时触发记录写明原因;评测结果给实际问的问题、没跑的题单独计 not_run、stop_reason 照实写;按需加入范围的留痕记上运行发起人;召回消息按种类写答案条数;撤销分享返回页面标题;E4 只算有口径卡的版本。验收:后端全量 14312 通过;tsc、文案检查;相关的 13 项浏览器检查 4423 项全过;四种库的方言容器测试全过;泄露扫描干净 2026-10-17 09:31:58 +08:00
ThearchyHelios 77b4c9c68a E4 的版本用量只算有口径卡的工作流
验收:E4 的用量把没有口径卡的普通发布工作流也当成口径计数。_e4 按(工作流, 版本)数所有 run_class=formal 的运行,
不看那一版是不是口径。

改法:数完之后按 WorkflowVersion 的图过一遍,只留图上有源头口径卡的版本(recall.source_cards:metrics 节点、不是
转抄别处口径的 caliber_from,和召回认口径卡的同一个判断)。比对里等价已证明的运行数(proven_runs)本来就只来自口径,
不动。写进了模块说明。

测试:test_ledger_api 新增一条:一个有口径卡、一个没有的已发布工作流各跑两次正式运行,E4 用量里只有前者、formal_runs
为 2。去掉修复回跑挂。
2026-10-17 09:19:24 +08:00
ThearchyHelios d9eaf8b850 撤销分享链接交回的 page_title 是页面标题,和建、列的一样
验收:DELETE /api/apps/{app_id}/shares/{share_id} 的返回里 page_title 是页面 id("home"),建分享时返回的是页面标题。
revoke_share 调 share_out(row) 时没给标题表,share_out 就退回页面 id。

改法:撤销照列表的取法(应用当前的版本 _previous 的 spec)给 share_out 标题表;撤销过的再撤销也一样。

测试:test_shares 的撤销用例加断言:建出来的 page_title 是「首页」,撤销、再撤销交回的都是「首页」。去掉修复回跑挂。
2026-10-17 09:19:24 +08:00
ThearchyHelios 590bfc9a59 口径召回的通知按种类分开写答案的条数
验收:ledger.recall 消息里写「答案:2 个」,实际是 1 个问数回答加 1 个正式运行。notify_recall 拿 _uses_of 的长度直接
拼成「N 个」,不分种类。

改法:notify/service 加 _answers_text,按用法的种类数(ledger.uses.KINDS 的顺序、KIND_TEXT 的叫法,同版本用量和召回
批次的说法)写成「问数回答 1 个、正式运行 1 个」;全局渠道按这一批汇总、个人渠道只数他的,两处都用它。只写条数,照旧
不放旧值、新值、差值和原答案的值。

测试(test_ledger_recall):新增一条:同一周一个问数回答、一次正式运行,升版召回之后全局渠道收到的「答案」一行是
「问数回答 1 个、正式运行 1 个」,消息里没有数;原来两条按「1 个」「2 个」断言的改成带种类的写法。去掉修复回跑挂
3 条。
2026-10-17 09:15:07 +08:00
ThearchyHelios 8f79098b6f 运行时 db_schema 按需加入探查范围的留痕记上运行的发起人
验收:db_schema 点名探查范围外的表、当场加进范围时,留痕(source_objects 的 added_by,trail_dict 的 by)是 null,
只有 run_id;look 那条路记着对话里的发起人。tools/datasource._on_demand 建 Trail 时没传 actor。

改法:查不在的原因时顺手按 ctx.run_id 取 Run.started_by,作为 Trail.actor 传下去。没有运行(ctx 没给 run_id)时照旧
为空。

测试:test_catalog_schema_truncated 新增一条:建一次 started_by 为「分析员甲」的运行,用它的 ToolContext 让 db_schema
点名一张范围外的表,留痕的 via 是 db_schema、run_id、ref(节点 id)对得上,by 是发起人。去掉修复回跑挂。
2026-10-17 09:12:29 +08:00
ThearchyHelios ccb2b2baa8 评测停止、中断、到了上限后的计数照实分开:没跑的题单独计 not_run,stop_reason 写停下的原因
验收:评测停止或中断后,没跑的题计入 errors、done = total、stop_reason 为 null,读起来像全评完了、出了很多错。
原因:runner._counts 把 cancelled、skipped 都算进 done(TASK_DONE),cancelled 又算进 errors;停止、中断走 _close →
_conclude(status, None, error),原因写进了 error、stop_reason 是 None;服务重启后的整理(startup、reconcile_stale)
和排队中就停掉(cancel_queued)只改了逐项状态,计数还是旧的、stop_reason 也没写。

改法:
- _counts:done 只算真的跑过的(ok、partial、failed);停止、中断时没评完的(cancelled)和到了上限、止损之后没开评
  的(skipped)单独计 not_run;errors 只算 failed;skipped 只算评了、但期望算不出、不评分的(verdict),不再混进没开评
  的。done + not_run + running + pending = total。
- 停止、中断是「停下」不是「出错」:_close 把原因记进 stop_reason(STOPPED / INTERRUPTED),error 留空;整体出错照旧
  记 error。到了上限、止损本来就写 stop_reason,不变。还没备好几臂就停下的那一支(bare)同样写 stop_reason 并重算计数。
- core/job_runtime 的 close_job、cancel_queued 加一个可选的 finish:状态改好、提交之前在同一个事务里补一步。评测的
  startup、reconcile_stale、stop 用它记 stop_reason、按改好的逐项状态重算计数(_closing)。起草、剖析、探查不传,
  行为不变(它们的测试全过)。
- stats.summarize 的 not_run 也只算没跑的(cancelled、skipped),出错的另列 errors(以前 not_run 里混着出错的)。

前端:评测页总览「N 项没评(停止、中断,或者到了上限、止损之后没开评)」和「M 项出错」分两行;类型补上 not_run、
errors 的说明。停下的原因本来就照 stop_reason 显示。

测试(test_eval_runner):停止之后 stop_reason 是「评测已停止」、error 为空,errors 为 0、done 是评完的题数、not_run
是其余,总表的 not_run、errors 同样分开;重启整理成 interrupted 时 stop_reason 是中断的说法、计数重算(not_run 1、
running 0);新增一条排队中就停掉的:not_run 等于题数、pending 归零;到了金额上限没开评的那题记 not_run、不记跳过。
去掉修复回跑挂 4 条。check-evals 的停止夹具照服务端改,核对停下的原因、不当成出错、没评的单列。评测、起草、剖析、
探查、定时维护相关的测试 548 条全过;tsc、check-copy 通过,check-evals 103 项全过。
2026-10-17 09:10:52 +08:00
ThearchyHelios a4486af90b check-evals:接住画布页起画布对话的 POST /conversations,免得偶发地漏到服务端
「口径命中与重复度」一节点「提取模板」会去画布(/studio/wf-drafted),画布页随后给这张图起一段画布对话
(POST /conversations {kind: canvas})。页面不关,这一下早晚不定:赶在最后那一节「写请求都在浏览器层拦下」之前
发出去就算漏到服务端。在 main 上连跑两次一次挂一次过,和这一轮的改动无关。照 check-ledger 的写法在假接口里接住
(交回一段空的画布对话),不进写请求的清单——不是评测页发的。改后连跑两次都过。
2026-10-17 09:02:57 +08:00
ThearchyHelios eb6abffc61 评测逐题结果给出这一题实际问的问题,模板原文另放 question_template
验收:评测结果列表里 question 是原始模板(带 {{ schedule.last_week_start }}),作答运行实际收到的问题已经渲染好了。
results 接口直接取的是 EvalCase.question。

改法:api/evals 的 _asked_questions 按执行时同一个算法、同一组输入渲染:题目模板 + 这次评测的截至时间(as_of,
建评测时就定下、重试不变)+ 题集时区 + 定时的 cron(runner._unit 交给 Driver 的就是这个)。题目在这次评测之后
改过(结果记的 case_hash 对不上现在的)时,现在的模板不一定是当时问的:改取作答运行输入里的 question,也没有
(反问、建图失败没有运行)就给 null,不拿现在的模板编一个。模板原文放 question_template。没有加库表的列:
渲染是确定的,不用另存。

前端:评测页逐题表的问法一格写实际问的问题;模板原文和它不同时(带变量,或题目改过)另起一行「题目原文:…」,
文案进 termsEval。类型补上 question_template。

测试:test_eval_runner 新增一条:带变量的题,结果的 question 和作答时 Driver 收到的一字不差、不含 {{,模板原文在
question_template;没有变量的题两者一样;题目改过、没有作答运行可取时 question 为 null、模板照给。去掉修复回跑挂。
check-evals 的夹具给带变量的那一题配上渲染好的 question 和模板原文,核对逐题表写的是实际问的、原文另起一行,
没有变量的题不多这一行。tsc、check-copy 通过,check-evals 102 项全过(漏到服务端的那个偶发问题另一次提交里修)。
2026-10-17 09:02:57 +08:00
ThearchyHelios f5c9f0c13c 剖析任务接口收取值观察范围,对话框给出「取值观察」;定时维护挑不出要观察的表时把原因记进触发记录
验收:取值观察只能经定时维护触发——POST /catalog/profile-jobs 的 scope 只收 needed、all,可剖析任务本来就支持
observe(只观察、不剖析)。另外 12 小时内观察过的表不再观察时,任务以 0 张表结束,原因只在剖析任务的 notice
里,从定时维护触发时触发记录(ScheduleFire.inputs)看不出来。

后端:
- ProfileJobIn.scope 加 observe(maintenance 是定时维护用的,接口照旧不收)。挑不出表时照旧 409 profile_nothing,
  说法是 NOTHING_TO_OBSERVE(「最近 12 小时内都观察过了」)。
- catalog_profile_jobs.nothing_reason:按此刻的表结构和目录一张表都挑不出来时交回 ProfileNothing 的原话;排在
  起草后面时说不准,返回 None。
- source_maintenance._start:建出 0 张表的剖析任务、这次触发又没有探查(开始时表结构不会变)、也没排在起草后面
  (目录不会变)时,判断得出任务会以 0 张表结束,把原因记进 inputs.skipped(同一套 NOT_RUN 说法进 reason)。
  任务照建、触发照旧是 started:每小时一次的维护不至于一天二十几次「没能发起」。同一次触发里有探查、或者排在
  起草后面时判断不了,保持现状,写进了模块说明。

前端:剖析对话框的范围里加「取值观察:有数据目录的 N 张表」(说法照维护设置里「取值观察」那一步:码值分布、
最新业务日期、按日行数和行数,和同口径的历史比出取值变化;最近 12 小时内观察过的这次不再观察),建任务带
scope: observe。张数按清单上有数据目录、不是视图的表算(isObservable,profile.ts),观察到期没有由服务端判,
所以是上限。挑不出表时说「没有要观察的表」和服务端原话,不给「改选全部表」(那是剖析,不是观察)。文案进
PROFILE_TEXT。

测试:test_catalog_observe 新增一条(接口建 observe 任务、只做观察检查,再建一次 409 profile_nothing,maintenance
422);test_source_maintenance 新增一条(只选取值观察,12 小时内再触发:任务 0 张表,inputs.skipped 和 reason 写明
原因)。去掉修复回跑两条都挂。check-catalog-profile 跟上:范围多一项 observe:1,说法核对;新一节建取值观察任务
(请求体 {scope: observe})、都观察过时的「没有要观察的表」且没有「改选全部表」。tsc、check-copy 通过,
check-catalog-profile 204 项全过。
2026-10-17 08:51:51 +08:00
ThearchyHelios c3173909db 整理:前两次提交里超过 120 字的两行折行,absent_message 进 source_objects 的 __all__
只动排版和导出清单,不改行为。
2026-10-17 08:42:26 +08:00
ThearchyHelios 9040289e1f 固化成口径草稿:口径卡用传入的名字、报告指令不写死代表那一轮的日期、指标名取目录中文名、已固化去重
验收报告里 certify.freeze 的四处:
- 口径卡的 caliber 用的是代表问题的原文,没用传入的 name。改成 name(去首尾空白)优先,没传才用代表问题。
- 报告的 instructions 写死成「回答:<代表问题>」,问题里带着那一轮的日期(「上周(10月5日到11日)」「九月第一周」),
  参数化之后这句就错了。有入口参数时改写运行时渲染的参数(「这次的参数:p1 = {{ input.p1 }},…;时间范围、筛选的
  取值以参数为准」),不写问题原文;没有参数时取数的字面量都是口径的常量,照旧写问题原文。
- 指标名直接用列名。现在能从数据目录取到中文名的用中文名:先看查询快照冻结的目录(schema_artifact,和口径比对用的
  同一份,ledger.match._frozen),老快照没冻结的看数据源现在的目录;只认列名本身就是目录里的一列(SELECT amount、
  SUM(amount) AS amount),gmv 这类算出来起的别名取不到,照旧用列名。
- 认证队列里 cluster 项的 frozen_into 把同一个工作流列了好几次:固化时同组的几次运行都记进 origin.sources,一项里
  的几次运行就各指一遍同一个工作流。shape 项同样会重。加 _frozen_of 按工作流去重(保持先后),三种项都用它。

测试(test_ledger_certify):原来的固化用例改成断言指令里没有代表问题和日期、有 {{ input.p1 }} {{ input.p2 }},
没传名字时口径卡照旧用代表问题,shape 和 cluster 两项的 frozen_into 都只有一个工作流;新增一条:传了名字的口径卡
用名字,目录里有中文名的列(amount → 金额)用中文名、取不到的照旧(n),没有参数时指令照旧写问题原文。去掉修复
回跑两条都挂。
2026-10-17 08:35:57 +08:00
ThearchyHelios 3f75cb1d2e 恢复被驳回的运行:照 end_reason 说「被驳回」,和继续运行同一个错误码 run_rejected
验收:对被驳回的运行调 POST /api/runs/{id}/resume,回的是「这次运行已取消,没有待处理的审批,无法恢复。已取消的
运行请重新发起」,/continue 却是对的(run_rejected)。resume 只看 status,cancelled 一律说「已取消」;存量的
failed + 驳回还会被说成「失败的运行可点继续运行」,而继续运行其实会被拒。

改法:runner 加 _resume_refused:cancelled + end_reason=rejected、以及加 end_reason 之前记成 failed 的驳回
(_rejected_before,同 continue_failed 的判断)抛 ContinueRefused(REJECTED_RESUME, code=RUN_REJECTED),别的照
_cannot_resume。resume 开头的状态检查、等审批凑齐时发现运行已经不在 interrupted 两处都用它。/resume 接口像
/continue 一样把带机器码的拒绝回成 CodedHTTPException(409, …, code)。ContinueRefused 是 ValueError 的子类,
别的调用方(待办服务)照旧按 ValueError 接。

测试:test_run_rejected 新增一条:驳回的运行 /resume 回 409 + run_rejected、说「被驳回」;手动停止的照旧说
已取消、不带这个码;存量 failed + 驳回也回 run_rejected,不再叫人点「继续运行」。去掉修复回跑挂。
2026-10-17 08:31:17 +08:00
ThearchyHelios c64c7a1062 目录接口对探查范围外的表照实说「在探查范围外」,不再说「可能已被删除或尚未探查结构」
验收:GET /api/datasources/{id}/catalog/{表} 对「对象索引里有、但在探查范围外」的表回 404「数据源中没有表 …,可能
已被删除或尚未探查结构」,而 /schema 和 /catalog/search 都说对了。_table_key 一律写死这一句,没看 absent_reasons。

改法:source_objects 加 ABSENT_MESSAGE 和 absent_message(),给人看的五种「不在」(表已不在、全库对象清单里也没有、
在探查范围外、在范围里却读不到结构、老缓存说不清)一句一句,和界面的 CATALOG_ABSENT_TEXT、/schema 用的
schema_view.absent_detail 同一套原因。上传表格、记录表按版本走,没有对象索引又没截断过的老缓存认不出名字是不是
从来就没有过:这两种只说「数据源中没有表 …」,不说「已删除」。用到的三处都换成它:_table_key(表详情、审阅、
使用记录等十来个接口共用)、表助手开始前的 404、批量审阅逐条的 table_missing 错误。

测试:test_catalog_schema_truncated 新增一条(205 张表、规则只收 200 张的合成库):范围外的表在表详情、表助手、
批量审阅里都说「探查范围外」,对象索引里也没有的说「没有表 …」。去掉修复回跑挂。
2026-10-17 08:28:54 +08:00
ThearchyHelios 7db9760121 用量计量拿到调用时实际用的模型名:评测汇总里助手用量不再记成 unknown
验收:评测汇总里助手用量的模型是 "unknown",写作用量的模型却是对的。写作用量来自运行的 llm.end(节点配置里
就有模型名);助手用量来自 providers/usage.Meter,它只从回调的 invocation_params 取 model / model_name,而演示
模型 MockChatModel 没有 _identifying_params,调用参数里只有 _type 和 stop,于是落到 UNKNOWN_MODEL。

改法两处:
- Meter:调用参数里取不到时,看 LangChain 照模型对象给回调的 metadata 里的 ls_model_name(调用时传的 model,
  否则对象上的 model / model_name),再取不到才看回复、才记 unknown。不认得调用参数的模型类也记得对。
- MockChatModel 补上 _identifying_params(model_name),和 OpenAI 兼容、Anthropic 一样在调用参数里报模型名。

测试(test_usage_meter):调用参数里不报模型名的模型、演示模型都按对象上的名字记;三种接入(OpenAI 兼容、
Anthropic、演示模型)由 factory 建出来,照 LangChain 回调时给的参数喂给计量,记的都是接入里配的模型 id,
调用参数里本身也带着;评测作答(eval/answer.Driver)走演示模型时助手用量记在 mock-fast 名下。两处修复都
去掉回跑挂 3 条,只留计量那处时挂「调用参数里本身带着」那一条。
2026-10-17 08:24:15 +08:00
ThearchyHelios caeab0fad6 SQL 差异说明认得同一列上的条件改写:说清「这次对 X 的条件是 …,口径是 …」
验收:口径 status = 'paid'、这次 status IN ('paid', 'refunded'),explain_sql_diff 只给兜底「两条 SQL 的写法不同,
未能归纳成具体差异」。原因是差异说明只说四类,同一列上两边各写一套条件(等号对 IN、取值集合不同、范围端点不同)
不在其中:_extra_filters 看到另一边也用了这一列就放弃。

改法:_Explainer 加 _rewrites,排在 _times 之后、_extra_filters 之前。同一张实表的同一列两边 WHERE 里都有条件、
至少一边有没配上的,就说「A 对 X 的条件是 …,B 是 …」;两边都只是取值集合、又有共同的取值时补「(这次多了
'refunded')」。两边都是时间条件时 aspect 是 time_range(FacetDiff 说明里早有这个方面、engine/compare 也按它
排序),否则是 filter 且 a、b 两边都有——dual_check_facts 对两边都有的 filter 本来就说「两边各有不同的筛选条件」
不写目录,ledger/stats、评测页的方面叫法都已认得这两个名字。

为了不说出不存在的不同,只在这些条件都满足时说:两边用到这一列的条件都只涉及这一列、比的是那一列本身;
按取值逐段算过两边留下的取值确实不同(_Range.compare 加 never_null:表结构里确定不为空的列不拿空值比;
x >= 100 AND x >= 50 对 x >= 100 这类冗余写法算出来一样,不说);不在 LEFT JOIN 可空一侧;WHERE 之外(ON、
HAVING、CASE、聚合参数)都没用到这一列(SUM(CASE WHEN status = 'paid' …) 配上 IN 可能和只筛 paid 一样);不是
认不准的时间窗口;没换表;有认不出列的条件时整段不说。

只改说明、不碰等价判定:说明只在已经判了不等价之后才跑。新测试把 _rewrites 换成什么都不做,逐对(语料全部
加几对改写、两种先后、给不给表结构)比等价与否和判定的级别,一字不差;IN 只有一个值、IN 列表去重排序照样判等价。
语料执行守门(意思一样的对不许说出具体不同)全过。

测试:test_sql_semantics 新增三组(各方言说两边、可能不影响结果的不说、等价判定不变);原来断言这两类只给
兜底的用例改成「算出来的值上换了值」(LOWER(status))仍只给兜底;test_sql_text_diff、test_dual_check_facts 跟上
(同一列上的时间范围现在是 time_range,照样不写目录;换了筛选的值不写目录)。去掉 _rewrites 的调用回跑,新测试
挂 5 条。

双盲复算的前端夹具 dual_check.json 里「说不清的」那个变体原来就是同一列上的时间范围,现在说得出了:换成套着
DATE() 的时间范围(认不出取值范围,仍只给兜底),test_dual_check_fixture 重新生成,check-verify 对应的说法和
高亮那一行的断言跟上。
2026-10-17 08:17:12 +08:00
ThearchyHelios 7f949cce92 取值观察:业务日期有未来值时不再误报量跌、缺天;「今天」统一按服务端所在时区
验收复现:业务日期最晚到明天、今天只写了几行,记出一条 volume_drop。原因有两层:
- 比较器 value_drift.daily() 取 last = max(days),只在 last >= today 时退一天;max 落在明天时退到的是今天这个
  还没写完的日子。改成最近一个整天 = min(有数据的最后一天, 昨天)。
- 按日行数的查询 day_volume_sql 只有下界,未来的日子也进了窗口。加上界:数到观察当天(含),第二天起不算
  (< 第二天,时间列上当天的时分秒照样算进来,文字存的日期按字符串比同样成立)。签名改成必须传 until。

缺天同样的问题也修了:今天以后的空日子不算缺天;以前那次观察只看到它自己那天(data.until)为止,免得它
窗口里未来的空日子被当成「以前就有过缺天」,挡住这一次真缺的天。断档遇到未来值时离今天是负数,只会报不出、
不会误报,观察本身照实记最新业务日期(目录里也照实给人看),不截未来值,写进了模块说明。

「今天」:原来窗口用 UTC 日期、比较器用 now.date()(也是 UTC),业务日期是本地日期,东八区凌晨 0–8 点会差
一天。统一成服务端所在时区(catalog_profile_observe.local_today,和待办汇总 notify.digest_at 同一个口径),
写进模块说明。

测试:test_value_drift 两条(未来值不算最近整天、未来空日子不算缺天且历史按 until 截);test_catalog_observe
两条(SQLite 真跑剖析任务,明天的行不进窗口、不记量跌;local_today 按 TZ 取本地日期)。去掉修复回跑都挂。
金样(tests/fixtures/dialect/*.sql)的 day_volume 一行随上界更新;scripts/dialect_it.py 加了一条「只数到观察
当天」的真库核对。
2026-10-17 07:59:19 +08:00
ThearchyHelios adfd783a07 合入下一轮第 4 波(收口,docs/design/next-round):口径召回(发布新版本后反查用过旧版的答案、按参数分组在同一份数据上重算两版之差、数变了才开召回待办、没变的只记账;目录事实与表结构变动标「依据有变」;版本用量与发布弹窗的召回预告、版本历史的召回批次);评测前端(导航「评测」、题集与加题、发起与进度、结果、对比与 A/B、口径命中与重复度、目录快照;定时页选目标种类;设置里的评测一组);口径账本前端(证据「口径」一步、问数据轮次摘要与出具 / 对账、对账反馈、可沉淀的问题、设置里的口径账本一组、比对结果轮询);目录前端(「变化」视图与处理、数据源角标、表详情的变化一节、定时维护、后台任务条);遗留:被驳回的那一步各处画「被驳回」、问数据建图用量不再是下限、比对结果实时、source.changed 与 ledger.recall 打开订阅。验收:后端全量 14284 通过;tsc、文案检查;本波相关的 21 项浏览器检查 7084 项全过;泄露扫描干净 2026-10-16 22:43:04 +08:00
ThearchyHelios ccf1fb21d2 check-all:第 4 波三项检查的耗时估计按实测改(只影响排队顺序) 2026-10-16 22:42:45 +08:00
ThearchyHelios c8cd56c108 README:第 4 波的升级说明(导航「评测」、口径召回、依据有变、被驳回的那一步、建图用量、两个新通知事件、后台任务条与定时维护);核心能力加「回归评测」「口径账本」两行;新增「回归评测与口径账本」一节和数据目录下「结构变化、取值变化与定时维护」一节;单进程前提补上后台任务与锁;检查清单 43 项 2026-10-16 22:33:59 +08:00
ThearchyHelios cc51c98df3 文案:删掉起草、剖析在页头和旧进度条上的几条说法(第 4 波起进度只在目录页的后台任务条上,见 termsSource 的 JOB_STRIP_TEXT) 2026-10-16 22:31:18 +08:00
ThearchyHelios d4e68bd1a9 合入 W4-d 目录前端:数据目录的「变化」视图与处理动作、数据源角标、表详情「结构与取值变化」一节、数据源的定时维护(一条目标为数据源的定时任务)、后台任务条(探查、起草、剖析按服务端排队顺序);打开 source.changed 订阅;指名数据源卡片统一用 #source-<id> 2026-10-16 22:30:09 +08:00
ThearchyHelios d17a08bafb 合入 W4-c 账本前端:证据「口径」一步与数字上的小标记、问数据轮次摘要与按口径出具 / 对账、对账视图与反馈、可沉淀的问题、设置里的口径账本一组、比对结果按退避轮询;被驳回的那一步 node.failed 带 reason=rejected,画布、航迹、时间线、问数据过程都画「被驳回」 2026-10-16 22:29:02 +08:00
ThearchyHelios 13bd021219 合入 W4-b 评测前端:顶级导航「评测」(搭建者以上、⌥0)、题集与四种加题、发起评测与预估花费、评测详情与逐题结果、对比与 A/B、口径命中与重复度、目录快照;定时页选目标种类、认得数据源维护的触发记录;记录页的评测来源;设置里的评测一组;问数据建图用量不再是下限(读完模型的流再关);问题聚类的向量只取一次 2026-10-16 22:28:35 +08:00
ThearchyHelios c26f4f2d30 合入 W4-a 口径召回:发布新版本后反查用过旧版的答案(问数回答、正式运行、固定它的版本与应用、导出),按参数分组在同一份数据上重算两版之差(差值在召回卡里算),数真变了才开 recall 待办、没变的记「已按 vN 核对,不影响」;目录事实和表结构变动标「依据有变」;版本用量与发布弹窗的召回预告、版本历史里的召回批次与接着算、recall 待办卡;团队渠道一次召回只推一条;账本接口带召回标记,对账结果可以反馈;E4 2026-10-16 22:28:34 +08:00
ThearchyHelios 1195c4abcb 账本前端补两样:答案身上的召回标记写到问数据的轮次和证据面板「口径」一步;对账结果卡上问「说明有用 / 看不懂」
复核 W4R-03(a×c):召回在原答案的运行上追加 ledger.recalled、ledger.basis_changed,以前只在运行时间线(decode)里,问数据的
轮次底部、证据面板「口径」一步、账本接口都不带——使用者被标了「依据有变」、或者口径升版后「已按 v2 核对,不影响」,重开对话
什么也看不到,得点开「过程」才翻得出来,而使用者进不了记录页。W4-a 已在账本接口加上 recall(ledger/recall.answer_marks:
checked / basis / tasks,几种 state 都带),这边照它画:

- typesLedger:RunLedger.recall(LedgerRecallMarks)
- run/LedgerStep 新增 RecallMarks(问数据的轮次和「口径」一步共用):「已按口径「X」vN 核对,不影响」(同一份口径核对过
  几次只写最近那一版,数变了的不在这里写);依据有变按两类各一行——数据目录(catalog / values / catalog_edit)和表结构
  (structure),认不出的种类只说「答案的依据有变」不猜,项数相加,按新目录新出现错误级问题的写几条;看的人手上有说的是
  这个答案的召回待办时写一句(口径升到 vN、数变了 / 依据有变检查出新问题)并链到 /apps/inbox/{待办}
- LedgerTurn:比对过的卡里写在摘要下面;没比对、不比对的答案(state 不是 matched)只要带着标记就单独写一张小卡
- LedgerPart(证据面板「口径」一步):有标签的写在脚注前;没标签但答案带着标记的,这一步只写标记

复核 W4R-10(多包):细案 02 做法 10 的 E2「说明有用 / 看不懂」以前没有入口。W4-a 已加 POST /ledger/answers/{run}/reconcile/
{对账运行}/feedback({verdict: useful | unclear},记成对账运行上的封存后事件、统计 E2 数它),账本接口的 reconciled 每一项
带 feedback {mine, useful, unclear}。这边:

- api.caliberLedger.feedback;typesLedger 加 LedgerFeedback、LedgerFeedbackOut
- run/LedgerReconcile 的对账卡:做完的卡问一句「「差在哪」的说明有帮助吗?」,两个按钮,看的人选过的按下(aria-pressed),
  写各几个人(服务端给的数),可以改主意;交回来的反馈先画上,账本再取一次让别处挂着的同一张卡跟着变;回收站里只看不反馈;
  没做完的卡不问
- 问数据的轮次里卡片上方没有「差在哪」,卡里补写一份(showWhere),反馈问的就是它;证据面板里它本来就在卡片上方,不重复

检查(写请求都在浏览器层拦下):
- check-evidence 新一段 ledger-recall:比对过的答案「口径」一步写核对过(只写最近那一版)、依据有变(项数相加、新问题条数)、
  链到待办;不比对的答案这一步只写依据有变
- check-chat 新一段 recall:轮次底部同上,另核对做完的对账卡写「差在哪」和反馈人数;不比对的答案单独一张小卡写表结构有变
- check-ledger 对账一段:没做完不问;点「看不懂」请求体只有 verdict、按下、写各几个人;改点「说明有用」再记一条、按下的换过来
- 共用夹具 ledger-fixtures 加 RECALL
把这几个文件的改动拿掉回跑:check-chat recall 6 项、check-evidence ledger-recall 4 项、check-ledger 对账反馈 2 项都不过;
放回去全过
2026-10-16 22:21:11 +08:00
ThearchyHelios f72e1d4a65 问数据、画布右栏、运行详情的步骤时间线:被驳回的那一步画停止的剪影、行尾写「被驳回」,不再是绿色的完成勾
复核 W4R-02:decode 已经给被驳回的那一步(node.failed 带 reason=rejected)记 status=rejected,但三处共用的步骤时间线
run/AssistantStream 不认它:BADGED 里没有 rejected,徽标落到「顶层节点画完成」那一支,被驳回的那一步成了一个绿勾;字色是
正文色,行尾 STOPPED 也没有这一项——副标题写着「张工 驳回:金额不对」,图标却说做完了。细案 5.3 要的是驳回之后各处都写
「被驳回」。

- BADGED 加 rejected:画 lib/status 里 rejected 那一套(停止的剪影、取消的中性色,和画布节点卡同一个)
- 这一行用次一级的中性字色(比取消、跳过的淡色重一档:运行就停在这一步),副标题(谁驳回、备注)用正体、不再是淡色斜体
- 行尾:STOPPED 加 rejected。被驳回的那一步带着耗时(node.failed 的 duration_ms),只写耗时的话停止的方块和取消分不开,
  写成「被驳回 · 900 ms」
- 长列表折起来时照样露出被驳回的那一行(notable 认 rejected):运行停在这一步,不能收进「展开前面的 N 条」
- check-chat「被驳回」一段:run-rej2 的事件换成「查数」那一步 node.failed 带 reason=rejected,点开执行过程核对这一行的
  状态、剪影(stop,不是 square)、图标不是完成的绿色、副标题和行尾写「被驳回」、不写「失败」。改之前这三项不过(徽标是
  done、颜色是 --st-done 的绿),改之后深浅两套都过
2026-10-16 22:18:44 +08:00
ThearchyHelios 464d1c0741 召回复核修正(前端):召回待办的系统通知去待办页、使用者不给重新出具的记录页链接、旧版写不再接着算的原因、时间线认对账反馈
- W4R-06:后台系统通知点开时,口径召回(不属于应用、挂在召回运行上)和使用者(进不了记录页)一律去 /apps/inbox/{id}。原来
  没有 app_id 的都去 /runs/{run_id}:使用者被送回应用首页,搭建者落到召回运行的详情页,那里没有这张待办卡。
- W4R-07:recall 待办里「重新出具的正式运行」只给搭建者链到记录页,使用者写「正式运行的记录由搭建者在记录页查看」(同问数据
  轮次下的出具结果)。
- W4R-12:版本历史里旧版还有没算的组却不能接着算时,照服务端给的 continue_reason 写「不再接着算:……」,不给按钮。
- decode 认 ledger.feedback(对账运行时间线上一条一行:谁给了哪一种反馈;认不出的不猜)。

检查:check-inbox 加使用者 / 搭建者看重新出具过的待办、系统通知点开去待办页两段(通知换成记录器,点它就是调 onclick);
check-publish 加之后又发布了更新版本的旧版不给接着算;check-decode 加 ledger.feedback 一段。去掉修复回跑,新加的几项都不过;
加上修复 decode、inbox、publish 三项 1110 项全过。tsc、check-copy 通过。
2026-10-16 22:16:58 +08:00
ThearchyHelios b3dcddb52e 召回复核修正(后端):人工节点不再挡召回、读不出召回卡记失败、旧版不再接着算、团队渠道一次召回只推一条、目录核对按数据源合并排队;账本接口带上召回标记,对账结果可以反馈
- W4R-01:召回只查新版图里会不会写外部系统(apps/backfill 抽出 graph_external_write,graph_side_effect 复用它)。召回图只有两版
  的取数和口径卡,图里别处的人工节点、按流程使用的问题碰不到它;口径卡上游的人工节点 derive 本来就认作数据部分不能复用。
  「按新版重新出具」走完整的正式运行,仍按 graph_side_effect 全套拒绝。原来带审批的口径升版后一组都不召回,L6 对它们失效。
- W4R-09:收尾时召回卡读不出、或缺了某个比较的旧值 / 新值,照实记重算失败(读不出召回卡),原答案一个不动。原来两边都是空,
  按渲染比被当成「没变」,给每个原答案永久盖上「已核对,不影响」,收过尾之后再也不核对。
- W4R-12:这一版已经不是当前发布版(之后又发布了更新的版本)时不再发起召回、不给接着算,批次里写 continue_reason,接着算的
  接口 409 带同一句。同启动时接着做只认当前发布版:新版本的召回覆盖更早的所有版本,再按旧版开「口径升到 vN」的待办只是添乱。
- W4R-13:开登录时一组答案几个主人就几条待办,全局渠道却按这一批(recall.batch_of_key:同一次召回、同一个来由)只在最早开的
  那条上推一次,答案、待办按这一批汇总,几条的链到待办箱;别的几条连 task.opened 也不再推全局渠道。个人渠道照旧每人一条。
- W4R-11:目录审阅之后的核对按数据源排队、批量审阅的几张表合成一遍(catalog_pass,同一数据源一把锁);查询快照按数据源在库里
  筛、按运行结束时间分页、每张表凑够 BASIS_MAX_RUNS 次运行就停;冻结的表结构快照这一遍里按工件 id 只读一次。原来批量审阅
  几十张表就同时起几十个后台任务,每个都全表扫查询快照、反复读同一份几 MB 的表结构快照。
- W4R-03(本包那一半):GET /api/runs/{id}/ledger 加 recall:checked(已按 vN 核对,不影响)、basis(依据有变:哪一种、几项、
  新出现几条错误级问题)、tasks(看的这个人手上说的是这个答案、还没处理的 recall 待办)。不放数、不放表名。几种状态都带。
- W4R-10(本包那一半):新事件 ledger.feedback(对账运行上的封存后事件),POST /api/ledger/answers/{run}/reconcile/{rid}/feedback
  {verdict: useful | unclear} 记反馈,同一个人改主意只算最后一次(app/ledger/feedback.py);账本接口的 reconciled 每一项带
  feedback {mine, useful, unclear};统计 E2 的 feedback 数到它,去掉「第 4 波接上」的占位说法。离线核对页、封存后事件摘要
  都认得这个事件。

测试:test_ledger_recall 新增七个用例、改了人工节点那一个(召回照算、重新出具照实拒绝);新增 test_ledger_feedback;
test_ledger_api 的 E2 断言跟上。每个修复都先写失败的测试、去掉修复回跑确认抓得住。后端全量 14237 通过。
2026-10-16 22:16:58 +08:00
ThearchyHelios 9886e10be2 账本接口:刚跑完未封存答 pending 只限结束后两分钟内,早就结束、一直没封存的照实答「运行还没有封存」
复核 W4R-08:上一次给 GET /api/runs/{id}/ledger 加的 pending 分支没有时间界限——成功结束、要比对、没封存的运行一律答
pending。它本来只为 runner 落库 run.finished 之后、封存之前的那一下(页面收到 run.finished 立刻来取)。封存出了错、或者是
封存这件事之前的老数据,会永远答 pending:每个轮次底部、证据面板都转两分钟「正在比对口径」,再取一次还是 pending;改之前
答的 ineligible「运行还没有封存,不比对」才是实情。

- ledger/view.py:新增 SEAL_GRACE_S = 120(和页面等比对结论的上限 store/ledger.ts 的两分钟同一个量级),_just_finished 看
  finished_at 在不在这段时间里(没记结束时间的不算;库里读回 naive 的按 UTC 算,同 db/base.UTCDateTime)。只有刚结束的才答
  pending,其余照旧走 ineligible(NOT_SEALED);_stamp 里的局部 datetime 导入挪到模块顶上
- 测试:刚跑完的那条补上 finished_at=现在;新增一条结束已久、一直没封存的和一条没记结束时间的,都答 ineligible、原因是
  没封存、不排按需比对。去掉 _just_finished 回跑,新测试失败(答的是 pending)
2026-10-16 22:13:52 +08:00
ThearchyHelios 7f5578c094 定时任务页认得数据源维护:触发历史列出建了的探查、剖析任务和没执行的步骤;「去数据源页设置」改链 #source-<id>(复核 W4R-05、W4R-04)
W4R-05 为什么:数据源维护的一次触发建的是探查、剖析任务,没有运行;api/schedules._fire_outs 不交触发记录的 inputs,
FireRow 只认 run_id 和 eval_run_id,于是每一次建了任务的维护都写成「已发起 · 未发起运行」,和数据源页「定时维护」的
「最近一次」对不上;「立即运行」一次维护还弹「未能发起运行」。

- 后端 api/schedules._fire_outs:目标是数据源维护的触发另带 inputs({steps, jobs, skipped},app/data/source_maintenance
  记在触发上的那一份,和数据源页「定时维护」读的同一个形状);别的目标给 null(工作流触发的 inputs 是按模板渲染的工作流
  输入,触发历史不列)。触发历史、页头「上次触发」、列表、立即运行的答复都走它。test_schedules_api 的 FIRE_KEYS 加 inputs。
- 前端 FireHistory:维护的那一行逐个列建了的任务(步骤、任务种类、编号、表数),探查链到数据源页那张卡片、剖析链到数据
  目录里那个任务的进度(?pjob=,同「最近一次」);没执行的步骤逐条写原因,服务端连成一句的原因不再重复;没建任务写
  「没有建任务」(刚触发、任务还在建写「正在建维护任务」),不写「未发起运行」。
- 立即运行(parts.runNow):维护开始了说「已开始维护」、详情逐行写建了什么;跳过照实说上一次维护还没做完;没开始说
  「没有开始维护」和原因。状态小标签的悬停同理。
- types.ts 加 ScheduleMaintenanceStep、ScheduleMaintenanceInputs(和 W4-d 的 MaintenanceFireInputs 结构一致,合并后
  交叉类型照样过 tsc);叫法进 SCHEDULE_TEXT(步骤叫法同服务端 STEP_LABEL,测试逐个对上)。

W4R-04 为什么:维护定时详情里「去数据源页设置」链到 /data/databases?source=<id>,数据源页(W4-d)只认 #source-<id>
(目录页后台任务条「查看」的约定),点过去落在列表顶上。统一成 #source-<id>:链接都经 model.sourceCardPath 出,
探查任务的链接同用它。

检查:check-schedules 新增「纯函数:数据源维护链到哪里、建了什么怎么写」「数据源维护的触发历史」两段(假接口:四种
维护触发、立即运行开始与跳过),改「链到数据源页」的断言;394 项全过。去掉 FireRow 的维护分支、链接改回 ?source= 回跑:
4 项失败。后端新文件 tests/test_maintenance_fire_history.py(立即运行一次维护后触发历史、页头、列表都带 inputs;工作流
触发不列渲染的输入;步骤和叫法前后端对上)。
2026-10-16 22:02:09 +08:00
ThearchyHelios d0082b4645 问题聚类的向量只取一次:评测页「口径命中与重复度」不再按窗口把问题重发给向量模型(复核 W4R-14)
为什么:这个页签一次打开,/api/evals/signals 按窗口调 compute_stats(缺省 6 个窗口,每个都聚一次问题),页面另调
/api/ledger/stats,一共聚 8 遍;chat/questions.cluster_questions 每遍都把窗口里的问题原文整批发给 embed_texts,
一次里重复的问法也照发。配了远程向量模型时每打开一次就是几百到几千次向量调用,慢、花钱。复现:本地 3 句问题各问 3 次,
一次打开每句被取了 9 次向量。

做法(改在全站唯一的取问题、聚类处 app/chat/questions.py,不动 ledger/stats 的统计口径):
- 问题原文 → 向量在进程里留一份(_vectors,最多 VECTOR_CACHE_MAX=1000 句、最近用到的留着),同一句话只取一次,
  一次里重复的问法去重后只发一句;/signals、/ledger/stats、认证队列、治理页的探索问题聚类都走它;
- 缓存认「哪一个 embedder、哪一个取向量的函数」算的:设置页换了向量模型(configure 换了对象)整份丢掉,不把两个
  向量空间的坐标混着比;取的这一会儿换了的,这一批照用、不留;
- 取向量按事件循环串行(每个循环一把锁,同项目里别处的写法):页面并行取的两个接口不把同一批问题各发一遍。

测试:test_evals_ui_api 新增「一次打开每句问题只取一次向量、再打开一次都不取、两个接口并行也一样」;
新文件 tests/test_question_vectors.py(去重、换模型丢缓存、取到一半换模型、上限与最近使用、并行只发一批)。
去掉缓存回跑:每句 9 次;去掉换模型的核对:2 条失败;去掉共用的锁:并行那条失败。
2026-10-16 21:41:30 +08:00
ThearchyHelios 034ac4b63b W4R-04 数据源页:指名一张卡片的地址全站只认 #source-<id>,带 &maintenance 打开它的定时维护
复核 W4R-04:定时任务页上维护定时的「去数据源页设置」链的是 /data/databases?source=<id>,数据源页只认 #source-<id>(目录页
任务条上探查的「查看」用的写法),没人读 ?source,点了落在列表顶上,既不滚到那张卡片也不打开定时维护。

改法按复核意见统一到 #source-<id>,数据源页这边:
- 新的 lib/sourceAnchor.ts 管这个地址的拼和拆(sourceAnchor / parseSourceAnchor / sourceCardId),两边各写一遍的话改一边
  另一边就落空。目录页任务条上探查的「查看」改用它,拼出来的地址和原来一样。
- DataSourcesTab 按 useLocation 的 # 处理:列表载入后滚到那张卡片;带 &maintenance 的再打开那张卡片的「定时维护」(只有
  手工登记的库才开,上传表格、记录表照旧没有这个入口),标记用过就从地址里去掉,刷新不再弹(同目录页的 pjob / djob)。
- 指名的数据源已经不在了(维护定时比数据源活得久,删数据源不删它):照实说「没找到这个数据源,可能已经删除」,不然只是
  落在列表顶上、什么也没发生。

定时任务页那边的链接(ScheduleDetail.tsx,W4-b 的文件)这里不动,要改成 /data/databases#source-<id>&maintenance
(或 sourceAnchor(id, 'maintenance')),check-schedules 的断言跟着改。

check-catalog-changes 加一节「链到一张卡片」:前面垫十张库让那张落在第一屏下(先有对照:不带地址时看不见);带 &maintenance
打开那张卡片的定时维护、滚到眼前、地址里只剩 #source-<id>;刷新只滚不弹;源不在了照实说;导入表格的源不弹;只是打开没有
保存,没有写请求。先写这一节跑出 6 项失败;修完 115 项全过;把打开、去标记、照实说三处去掉回跑,4 项报错,已还原。
2026-10-16 21:37:25 +08:00
ThearchyHelios 4a81ad25bf check-auth:导航从九项变十项(搭建者、关登录各一处)
第 4 波加了顶级导航「评测」(搭建者以上可见,评测-D8):check-auth 里「搭建者:导航九项」「关登录:导航九项」两处按数目断言,
跟着改成十项,搭建者那处另断言「评测」在里面;使用者那处(只有应用和设置)不变。check-auth 不在 check-all 的清单里,另起一套
后端 + vite 跑了「导航」「关登录」两段,全过。
2026-10-16 20:55:22 +08:00
ThearchyHelios 78252fdfa2 测试:评测页的前端取值和服务端常量逐个对上(tests/test_frontend_eval_unions.py)
typesEval.ts 的联合类型(状态、发起方式、题目种类、结论、作答路径、期望种类、期望答案来源、升版处置、试算结论、各期望的结论、
转移、归因、目录视图、E1/E3 档位)和 termsEval.ts 里对应的叫法表,直接读文件和 app/eval、app/core/job_runtime、api/evals 的常量比:
服务端加了一种(比如作答路径「被驳回」)前端没跟上,界面会写出英文原值;同 test_frontend_type_unions.py 的写法,另开一个文件
免得和别的包改同一个文件。
2026-10-16 20:46:18 +08:00
ThearchyHelios badd610cd2 评测页补齐:工作流题、手动清理更早的明细、逐题明细里的作答经过和答案原文
前三波的接口这一波都要有界面(收口):
- 加题时「写 SQL 定期望」「选口径」两种可以选题目种类——问数据题(问法交给助手)或工作流题(固定一个已发布版本、按入口字段填
  输入模板,考的是这一版本身);题目表里工作流题写工作流和版本。反问、从运行认定只对问数据题有意义,不给选。
- 评测记录页签加「清理更早的明细」(POST /suites/{id}/cleanup,先确认、写清后果;收尾时本来就按保留规则自动清,这里是手动再清一次)。
- 逐题表展开时读这一题的明细工件(GET …/results/{id}):自动重来了几次、作答的经过、答案原文——答错的题能看到它当时答了什么。

check-evals 跟着加三处(工作流题的请求体、清理先确认再发、明细),101 项。
2026-10-16 20:41:50 +08:00
ThearchyHelios 45c1ede402 评测前端:顶级导航「评测」、题集与加题、发起评测、评测详情、口径命中与重复度、目录快照;定时页选目标种类;记录页评测来源;设置里评测一组
为什么:前三波评测只有接口,这一波是收口——每样能力都要有界面、能走通(细案 01 第 18 项、第 15 项定时的前端部分,评测-D8)。
界面层不放逻辑:比率、结论、趋势、分档、能不能做都由服务端给(上一次提交在 api/evals.py 补的 latest、trend、actions、
preview、signals、逐题花费),界面只显示。

- 导航:「评测」排在设置前面、⌥0,搭建者以上可见(使用者的页面表在 visiblePages 里收窄,手输地址被送回应用首页)。导航从 9 项
  变 10 项,在 600、520、480 像素高的窗口里重新量过:≤520px 那档的导航项从 32px 收到 30px(17px 图标 + 2px + 11px 字),
  不然 480 高时遥测点超出视口 12px;App.tsx 的说明跟着改。
- 评测页 pages/evals/*(类型 typesEval.ts、接口 api/evals.ts、文案 lib/termsEval.ts 的 EVAL_TEXT):题集列表(最近一次、同一
  变体的趋势、定时,没有定时给「设定时」带着题集去新建);新建、导入(先预览)、导出、归档、删除、题集设置(时区、默认变体——
  定时评测按它评、预算只填要改的项);题目表(启用、试算、编辑、删除),口径升版待处置的顶部提示和三选一处置(叫法由服务端给,
  没有缺省);加题四种方式:写 SQL 定期望(选数据源、写 SQL、预览、点选格 / 列 / 配对列、按维度找行、试算,遮罩列拒收的原话
  落在 SQL 下面)、选口径(工作流|口径卡|指标,不能复用的照列写原因,口径的输入按那一版的入口字段填)、从问数据运行认定
  (选运行、选查询、选取哪一列,用到遮罩列的查询不给认定)、期望没有数据或期望反问;可另加文字要点。数值期望不许人填:只点选
  取哪一格。
- 发起评测:评一次 / A/B 对照(两到三臂)/ 目录贡献对照(预设,可加「只用已核实和已确认的项」),变体有助手、写作模型、结论
  裁判、目录(当前 / 只用已核实的 / 关 / 快照)、重复次数;估算和发起是同一份请求体,项数、按上一次估的花费、生效的预算、今天
  已花照服务端写;可点名和哪一次比。
- 评测详情 /evals/runs/:id:进度和每题正在做什么、停止、只重试没做完的、按新规则重评、设为基线(按钮照服务端的 actions 摆);
  总览卡片(准确率和可追溯准确率带区间、花费、逐题 E1)和各项分布(结论、作答路径、出具档位、复核、结论裁判、引用率、查看、
  耗时、按角色的用量);逐题表(结论、期望和答案里的数、弱匹配、SQL 差在哪、查看、耗时、花费,展开看原因、去运行详情;
  ?case= 定位那道题);和上一次比(换基准、指纹差异、转移和归因);A/B 配对表(都对 / 只 A 对 / 只 B 对 / 都错、p 值)。
- 「口径命中与重复度」页签:E1、E3 这一窗口的值和档位、参考线、往前几个窗口的趋势(GET /api/evals/signals),明细直接调口径
  账本的 GET /api/ledger/stats(总方案 X2);成员不少于 3 的问题类能加入题集(带着问法去加题)、提取模板(从最近一次的运行提取,
  去画布)。目录快照页签:拍当前目录、影子起草(先估算再开始,能停)。
- 定时页:新建时先选定时什么(工作流 / 评测题集;数据源维护在数据源页建),评测题集的表单(pages/schedules/TargetEditor.tsx:名称、题集、
  FreqPicker、补发宽限,建题集目标用 ScheduleTargetCreate),评测题集的定时在详情里能改名称、频率、时区、补发宽限(SchedulePatch,
  只交改了的、带版本);数据源维护的定时只读、链到数据源页,第 3 波「只能查看,不能修改」那句改成说清在数据源页设置;触发历史里
  的评测链到评测详情。纯函数 targetFormOf / targetCreateBody / targetPatchBody / targetProblems 放 model.ts。
- 记录页:评测运行旁的「评测」标记写是哪一步(作答、算期望……),点了回到评测里那道题;运行详情页头有键盘到得了的链接
  (pages/runs/EvalSource.tsx)。
- 设置:偏好设置里「评测」一节(pages/EvalSettings.tsx,SettingsPage 里加一行):四项预算缺省、保留几次、缺省开不开结论裁判、
  今天已花;自己存、只交 eval 一组,取值范围只在服务端判。
- 问数据用量(评测-D14 的界面一半):复核慢过问数据页的等待上限时,答案照原样先交出去,复核那一次的用量晚到了照记进这一轮、
  再落一次库(以前直接丢掉);开发期 window.__chatReviewWait 让检查脚本把上限调短。

检查:check-evals.mjs 换成真检查(假接口加夹具,写请求在浏览器层拦下并断言请求体,98 项);check-shell 导航十项、⌥0、三种窗口高;
check-schedules 目标种类(纯函数和页面);check-chat 用量那一段加复核晚到。
2026-10-16 20:38:07 +08:00
ThearchyHelios 9ad6c035d0 口径账本的界面检查:check-ledger 换成真检查,check-evidence、check-chat 各加一段
都用 page.route 假接口加夹具(scripts/ledger-fixtures.mjs:GET /api/runs/{id}/ledger 的形状照服务端 run_view,挂在可点击
证据的夹具 evidence-doc.json 上,只用通用名),写请求在浏览器层拦下、核对请求体,认不出的写请求一律记账、结束时必须为空。

- check-ledger(骨架里的占位换掉):
  · 比对还没出结果:「口径」一步写「正在比对口径」、按退避再取(间隔越来越长),等满了照实说、给「再取一次」、不再取,
    点了重新取、比对过了就画出来,之后不再取(store/ledger 在开发构建里挂 window.__ledger,把等待起点挪到两分钟前);
  · 三种情况:来自口径(口径、级别、怎么认的、参数、事后补比的说明)、相关口径(差在哪 + 看差多少)、这次的推理;
  · 对账:参数要核对时表单直接打开、照入口字段画 → 发起带核对过的参数(空着的不送)→ 409 带回的选项画「选择要对照的
    指标」、一组没选不发起 → 选好再发起带上对照 → 结果卡片先写进行中、再取一次后画出按你的问法 / 按口径 / 差值 / 相对差,
    点差值打开出处链;
  · 可沉淀的问题:工作流列表弹窗里的抽屉,三类来源分开写、各写怎么认出来的;聚类只按那一轮固化;「不是口径」不写理由
    不能确认、写了才记下并拿掉这一项;固化走 from-run 的 freeze(带同组的别的运行和来源轮次)、打开画布里的草稿;
  · 使用者:不能出具的照服务端的原因写「请搭建者出具」、不摆按钮,对账照样能用,出具过的正式运行不给链接、写由搭建者查看;
  · 设置里口径账本一组:显示生效的值,不合规的值写范围、不让存,保存条写改了哪几项,整组写 ledger。
- check-evidence「口径账本」一节:来自口径的数字挂「受管 / 已发布」小标记(紧跟数字、悬停写口径和认法、读屏念在数字上),
  相关口径、这次的推理、没比对的不挂;面板「口径」一步在出处链最上面,四种标签各写各的,不是数的片段不画;同一次运行只取
  一次账本。别的节的夹具一律答不比对,不落到真服务端。
- check-chat「口径账本」一节:交付了的轮次底部先写「正在比对口径」,按退避再取到比对出结果后写摘要、比完不再取;按口径正式
  出具、对账按钮照服务端的动作摆,出具的请求只说按哪份口径,出具过的正式运行挂在轮次下面(档位、打开运行);对账请求带
  哪条查询、哪份口径、核对过的参数。
2026-10-16 20:34:21 +08:00
ThearchyHelios e48b258449 W4-d 收尾:队列里的任务结束时重取变化计数和清单;定时维护里不给探查任务点了没用的「查看进度」
- 目录页:后台任务条的队列里有任务走了(结束了)就重取变化的计数、「变化」视图重取一页;走的是探查任务时清单也重取(表结构
  变了)。起草、剖析结束时页面跟着的任务本来就会重取清单。
- 定时维护「最近一次」:剖析任务的「查看进度」到数据目录页打开那个剖析任务(pjob);探查任务没有另外的进度页(进行中时
  进度就在这张数据源卡片上),不再给一个关上对话框就什么也看不到的按钮。check-catalog-changes 补上这两条。
2026-10-16 20:14:12 +08:00
ThearchyHelios bbf6ebb79d 召回收尾:启动时只接着做当前发布版的自动批次、补测重启后从已有召回运行重算计划;时间线认不出的依据种类不猜
- ledger/recall.resume:最近发布、之后又发布了更新版本的不再接着做(新版本的召回本来就覆盖更早的所有版本)
- 测试:重启前只发起了一组、也没收尾,重启后接着发完自动那一批、补上收尾照样开待办,再重启一次不再发起
- run/decode:ledger.basis_changed 认不出种类时写「答案的依据有变」,不当成目录事实变了;batches 的说明照实写参数原样给搭建者
2026-10-16 20:11:46 +08:00
ThearchyHelios 9252e6bb0e W4-d 检查:check-catalog-changes 换成真检查;check-catalog、check-catalog-profile、check-catalog-loop、check-capabilities 跟上
- check-catalog-changes(骨架里的占位换掉):假接口加夹具(虚构的网店库),写请求在浏览器层拦下、断言请求体。守的是「变化」
  视图的分组(要处理 / 提醒 / 说明,组内照服务端的先后)、两种筛选进请求和地址、刷新后还在;一条变化的依据、前后、影响面
  (目录项现在的状态、「这条 SQL 现在会报列不存在」、模板链到编排页那个节点、有效记录条件);动作照服务端给的 actions 画、做不了
  的写原因;清理先确认、加入码值带含义、知道了、误报的请求体,误报没写理由(含只填空白)按钮不能点;处理完写目录版本、建了的
  起草任务点得进进度;表详情一节(变化、撤销过的「已列全」、四种观察和口径、口径换过的提醒、断档的日子也在小柱图里);数据源
  角标(读屏写全、点了到「变化」);定时维护缺省关、开启时提示低峰时段、建(target_kind=source_maintenance)和改(PATCH 只带
  改了的和版本)、步骤走 PUT、最近一次建了哪个任务和哪几步没执行;后台任务条按服务端的两种先后、页头读屏不写数字、提醒在条上
  写全文、「查看」打开对应的对话框、探查的到数据源卡片;窄屏不撑宽页面。去掉排序、去掉「没写理由不能点」回跑,这几项都会报出来。
- check-catalog、check-catalog-profile:DraftStrip 的断言换成后台任务条(data-catalog-job-strip、data-catalog-job),页头的
  「起草」「数据剖析」只断言读屏写状态、不写数字;剖析的「最近查询多数超时」改在任务条上断言全文;check-catalog-profile 的假接口
  按建的先后给出队列,两种排法(起草在前 / 剖析在前)的文字都断言;窄屏下任务条看得见。三个目录检查都给变化、观察、后台任务、
  upkeep 配上空的假接口,不把假的源放行到服务端去查。
- check-catalog-loop.mjs 的 PROFILE_ON 换成 table_max_queries: 40、table_max_s: 60(和 check-catalog-profile 的 DEFAULTS 一致,
  05 (g))。
- check-capabilities:全局渠道可订阅的事件里有了「数据源有变化要处理」(第 4 波打开了订阅),登记了还没推送的只剩召回。

本包相关的检查(catalog-changes、catalog、catalog-profile、catalog-loop、capabilities、manage)在另起的一套后端 + vite 上都过了。
2026-10-16 20:05:43 +08:00
ThearchyHelios 35583ba1d8 口径召回前端(W4-a):版本用量加问数回答和召回、发布弹窗预告召回规模、版本历史看召回批次、recall 待办卡、时间线认两个新事件
为什么:前三波召回只有接口;这一波收口,口径升版之后谁的答案受影响、重算了几组、数变没变、怎么处置都要在界面上走得通。

- canvas/versionUsage:使用情况那一行加问数回答、导出、定时任务、召回(老服务端不给就不写)
- canvas/RecallPanel(新):发布弹窗「召回」一行——旧版本被谁用过、按参数去重几组、发布后自动重算几组、超出上限几组(可在
  版本历史接着算)、上限为 0 时只列不算、不能重算的原因;版本历史展开一版——每组结论(数变了 / 没变 / 无法重算:原因 /
  重算失败 / 正在重算 / 未重算)、变了的指标、开了几条待办、召回运行链接,「另有 M 组未重算」+ 接着算
- run/RecallTask(新)+ TaskCard:recall 待办卡——旧口径、新口径、两版之差一行一个指标,每个数点得开召回卡的指标链;每个答案
  当时的值点得开(正式运行的口径卡、问数回答的查询快照),问数回答链回对话;「按新版重新出具」(不能时停用并写服务端给的
  原因)、「知道了」;遮罩值写已遮罩、点不开;目录有变、表结构变了两种只有「知道了」
- run/decode:ledger.recalled(已按 vN 核对,不影响;召回核对数变没变;试算结果)、ledger.basis_changed(依据有变、依据的
  表结构已变);缺字段不猜
- 文案进 lib/termsRecall.ts;接口 api/recall.ts、形状 typesRecall.ts;TaskKind 加 recall
- 检查:check-inbox 加 recall 卡两段,check-publish 加召回预告和召回批次两段(版本历史、发布弹窗都在这里测;check-versions
  测的是上传表格的版本页,和召回无关),check-decode 加两个新事件的夹具,check-capabilities 的可订阅事件跟上 ledger.recall
2026-10-16 20:05:24 +08:00
ThearchyHelios b24aabefcf 账本前端:证据「口径」一步、数字上的小标记、问数据轮次摘要与出具 / 对账、可沉淀的问题、设置里的口径账本一组
第 2、3 波只有接口,这一波接上界面(docs/design/next-round/02-口径账本.md 做法 3–6、8 的界面、做法 11;总方案 X3、X10)。
界面层不放逻辑:标签、整题判断、能不能出具、能不能自动、不能的原因、要不要先核对参数都照 GET /api/runs/{id}/ledger 给的画。

- 比对结果不靠实时流(第 2 波遗留):ledger.matched 在封存之后追加、事件总线已经关了,打开着的页面收不到。store/ledger
  按退避轮询(1、2、3、5、8、13 秒,之后每 15 秒),服务端答 pending 时写「正在比对口径」,等满 2 分钟还没结论照实说、
  给「再取一次」;要自动出具的再等出具的那一次出现,出具、对账的运行没结束的等它们结束。只在有组件看着时轮询,同一次
  运行的正文、面板、轮次摘要共用一份
- 证据正文(EvidenceDoc):来自口径的数字后面挂一个小标记,写明受管 / 已发布,悬停写是哪一份口径、怎么认的;相关口径的
  数不加标记
- 证据面板出处链最上面加「口径」一步(run/LedgerStep):来自口径——「X」v3(受管)· 参数 · 等价已证明 / 助手选用 ·
  按口径正式出具;相关口径——差在哪 + 看差多少;这次的推理——没有相关的已发布口径;没比对的写原因;脚注写「封存后比对,
  不在封存范围内」,事后补比的写按哪种口径回看
- 口径对账(run/LedgerReconcile):核对参数(照动作里的入口字段画,推断的参数要先核对,遮罩值不回填)→ 发起(认不出列
  怎么配时照 409 带回的选项选对照的指标)→ 结果卡片:每组按你的问法、按口径、差值(附相对差)各自点得开出处链
  (apps/EvidenceDrawer,同应用页点数)
- 问数据轮次底部(run/LedgerTurn):一行摘要(几个数来自口径「X」vN、几个是这次的推理、几个没有比对)、整题等价时按口径
  正式出具(能自动的写正在自动出具;不能的照写原因,使用者没有应用授权写「请搭建者出具」)、有相关口径时对账;出具过的
  正式运行挂在下面,档位写完整出具 / 降档出具 / 不予出具,搭建者点开去运行;回收站里的对话只看不发起
- 可沉淀的问题(pages/ledger/CertifyQueue):工作流列表弹窗里的抽屉,确定性重复、问题聚类、被反复用的答案分开写;
  「固化成口径草稿」走 /copilot/from-run 的 freeze 并打开画布,聚类没有共同的 SQL、按人挑的那一轮固化;「不是口径」
  要写理由
- 设置(pages/settings/LedgerSettings,照 VerifySettings):自动按口径正式出具、每日上限、比对时限、升版后每次最多重算几组,
  和其余偏好共用保存条、整组写 ledger
- 类型 typesLedger.ts、接口 api/caliberLedger.ts(挂 api.caliberLedger)、文案 lib/termsLedger.ts;types.ts 的证据片段
  答复加 ledger、rendered 两个键
2026-10-16 20:02:08 +08:00