Commit Graph

238 Commits

Author SHA1 Message Date
ThearchyHelios bc4ea277e9 数据目录闭环(前端)复查修正:部分完成的宽表也写「已写进目录 N 段」(段进度都结束了,看不出写进了几段),服务端原因里已经写了的不重复;表助手「补上留空的列」超过 20 列时写明一共几列;流式回答每来一段只重画正在回答的那一轮;答完的一轮没有用量、没有查询时不再露出一个 0;check-catalog 补部分完成的那一条 2026-10-14 08:51:23 +08:00
ThearchyHelios a6e5b857fe 数据目录闭环(前端):数据目录页左栏加「审阅队列」视图——照服务端的优先级列出推断项,每项写位置、所在表、值、说明、为什么排在这里、来源和状态、所在表的使用次数,按项(影响数字的项 / 名称和含义)和表筛选(记在地址里),多选成批确认、驳回、撤销审阅(逐表带读到的版本,逐条的结果原地标出、冲突的写明),顶上是审阅进度(常用 20 张表、全部表、影响数字的项),点开一项右栏是所在表的详情(滚到那一项、列出用过这张表的运行),详情里改过之后队列跟着换状态;页头加「导出目录」(下载服务端给的文件)和「导入目录」(选文件 → 预览对上的表、新增 / 更新 / 保留 / 冲突 / 跳过,冲突逐条列出 → 确认导入 → 逐表写入后的版本,起草任务进行中、文件格式不对时照原样写服务端那句话);新检查 check-catalog-loop(表助手、审阅队列、导出导入、防错事实的说明和纯函数,用 page.route 假接口),登记进 check-all 2026-10-14 08:44:49 +08:00
ThearchyHelios 1cc9fe1a3d 数据目录闭环(前端):表详情加「表助手」——顶部和上次起草的提示里都有「和助手一起完善」入口,对话流式显示、能停止,助手跑过的只读查询写 SQL 和前几行(默认收起),修改提案逐项写改前、改后、依据并能逐项去掉、加回,「待保存的修改」跨多轮累积(同一项以最后一次提案为准),一键保存(最多 200 项,409 时按最新内容重算后停下来再看一眼),没开数据剖析的源写明只能根据表结构和目录推断、不能查数据,有留空列时开场引导先问这几列,有待保存的修改时换表、关闭先问;表详情加「用过这张表的运行」、有效记录条件和去重规则的推断项在值下面写说明(剖析核对的排除比例或没核对的原因)、从审阅队列打开的那一项标出来;起草任务逐表显示块进度(段被拆小后看得出来)和已写进目录的段,停止后写明已写进几段、只重试时接着起草,清单和表详情在最近一次停止、中断又没有新写入时接着用再之前那次起草记下的留空列数提示;check-catalog 加一节按约定的新字段推进 2026-10-14 08:44:37 +08:00
ThearchyHelios ead8ea216b 数据目录起草(前端):表结构里已经没有的表(只剩目录)不再给「重新起草这张表」「补充起草要求」——服务端只会把它记成已跳过。表详情顶部照写上次起草的结果(没写全的原因、留空了几列),不再建议补充起草要求后重新起草,写明「表结构中已没有这张表,不能重新起草」;清单上留空列的轻提示照旧,悬停里不再建议重新起草。起草设置收到的预先选好的范围(表详情的「补充起草要求」、结果里的「重新起草这几张表」)里的表已经不在表结构里时不再退回别的范围:那一项照旧选着,写明「表结构中已没有这张表,不能起草」(只少了几张时写其中几张不会起草),不能开始,也不默认勾用模型、不把焦点放进起草要求——以前退到「使用次数最多的 20 张表」还勾着用模型,以为只起草这一张,实际按别的范围起草了;选的那一项不在了时,单选框照实际起草的那一项勾。check-catalog 新加一节:只剩目录的表的清单提示与详情;打开详情以后表才没了(清单重取了、详情没重新载入)时「补充起草要求」打开的设置;重新打开后不再给两个按钮。check-all 里数据目录的耗时按实测改成 140 秒 2026-10-13 21:13:15 +08:00
ThearchyHelios 912bc3f107 check-catalog:假服务端给的提醒原文和宽表没写出来的原因照服务端的原样写——提醒是「最近 6 次调用有 4 次没写出来(额度用完 1 次、超时 3 次)。可以在「设置 → 偏好设置」的「起草模型」换一个模型、减少这次起草的表,或者停止这次起草」(原因按额度用完、超时、只给空壳、出错的顺序列);宽表的原因在列范围之后接着写「这一段没写出来;已拆小重试仍没写出」。以前是照约定自拟的一句,和服务端实际拼出来的不一样,只影响检查的逼真度 2026-10-13 21:09:49 +08:00
ThearchyHelios b91a652efe 数据目录起草(前端):模型拿不准、留空的列(中文名和含义都没给)单独写出来,不算没写全、表照样是已完成。起草对话框逐表写「12 列模型拿不准、留空了」,列名悬停看得到、也可以展开(最多 5 个,没列全写一共几列);结束后写合计「共 13 列模型拿不准、留空了(2 张表)」和办法——在起草要求里补充缩写和术语的含义,再重新起草这几张表,已有的内容不会丢;「重新起草这 N 张表」回到设置,范围就是这几张、勾着用模型、焦点在起草要求,补完再开始;结束后默认列出的表连同有留空列的(「只看未写全、有留空列的表」);关着对话框时结束的提示也接着写留空的列;设置阶段的「上一次起草」都写完了、只是有留空列的也提,写明几列。清单上上次起草有留空列的表一行淡色轻提示(不是失败标记,和失败、部分完成的标记分开;还在起草的那一次不算「上次」);表详情顶部同样提示(只有留空列时是提示、不是失败;部分完成又有留空列的并在一条里),给「重新起草这张表」和「补充起草要求」(打开起草设置,范围只有这张表)。类型加 CatalogDraftTask.blank_columns、blank_sample,CatalogDraftJob.blank_columns,last_draft.blank_columns(老服务端没有,按 0)。check-catalog 新加一节覆盖逐表与汇总、展开列名、默认列表、清单轻提示(颜色同次要信息、不是警告色)、进行中不算「上次」、回到设置重新起草(先存起草要求再建任务)、结束提示、表详情的两个按钮,窄屏展开列名一并量;check-all 里数据目录的耗时按实测改成 130 秒 2026-10-13 20:30:18 +08:00
ThearchyHelios a0b06f93c4 数据目录起草(前端):调用接连没写出来时,进行中醒目显示服务端给的提醒(job.notice)——提醒的样式、不是错误,写在进度条下面;关掉对话框时目录页上方的进度也带着这一行(全文在悬停里);好转后服务端清掉就收起,任务结束后不再显示。用量那一行接着写没写出来、超时的次数(没写出来的次数里含超时,写成「没写出来 4 次(其中超时 3 次)」,不读成两个数相加),有超时时写明「超时的调用不计用量,实际用量可能更多」;额度用完、超时多了服务端把之后的段缩小时写明「之后的段每段最多 20 列」。类型加 CatalogDraftJob.part_columns、notice,usage 加 timeouts、failed_calls(老服务端没有这几个键,按 0 和 null 处理)。check-catalog 的假服务端跟着给这几项,新加一节覆盖提醒的出现与消失、超时和没写出来的次数、段缩小的说明、任务结束后提醒收起,窄屏的起草弹窗和上方进度带着提醒一并量;宽表没写出来的原因照新写法写明列的范围(第 3 段(promo_attr_19 到 promo_attr_43,共 25 列)) 2026-10-13 20:26:52 +08:00
ThearchyHelios 0dbfeffb23 check-catalog:409 之后「取的是进行中的那一个」原来恒为真(计数 >= 0),改成等到确实在取那个任务的进度;补「任务进行中离开数据目录页(页内跳转,页面卸下)以后不再取进度」,之前只查了结束以后不再取;设置阶段先等上一次起草取回来再让别处建任务,免得它晚到、取回的已经是进行中的任务而走不到 409。假服务端的说法照后端的原话:起草模型用不了是「无法由模型起草数据目录」(原来还是「由助手」),已有任务、任务不存在、已经结束、没有可重试的表、起草要求超长同样对齐;起草要求的请求没有 guidance 这一项时同后端回 422;重试建的任务带 retry_of。types.ts 的 CatalogDraftJob 加可选的 retry_of(约定里没有、后端多给的,界面不用) 2026-10-13 16:34:46 +08:00
ThearchyHelios f57c6e284b 数据目录起草的几处说法照服务端的实际做法改:点停止后写「正在停止:取消进行中的模型调用,正在写入目录的表写完后停止…」(服务端马上停掉进行中的调用、只等手上那张表写完,不是等当前这次调用结束);任务整体出错时原因照服务端的原话在「起草失败」下面写一次(服务端的原因有的自带「起草任务出错:」开头,界面不再套一层),服务端给没结束的表记的同一句不再逐表重复(服务重启中断同样),各有原因的照写;「只重试失败的表」没建成和开始时同一个说法——起草模型用不了(服务端重试也回 409 catalog_draft_model_unavailable)照原样写那句话、长句不再拆成「标题:原因」,别的写「未能开始起草」;提示里原因为空时不留冒号。check-catalog 先补会失败的检查:停止的说法、重试时起草模型用不了、任务整体出错(原因只写一次、逐表不重复、都能重试),服务重启中断的逐表不再重复原因;假服务端的中断任务照后端记上同一句原因 2026-10-13 16:34:29 +08:00
ThearchyHelios f4ef5919bd 数据目录:正在编辑一张表时,它的「重新起草这张表」先不给点并写明先保存或取消——起草会写进这张表,编辑中的保存就会撞上版本冲突;check-catalog 补一项 2026-10-13 15:34:12 +08:00
ThearchyHelios 8795475207 check-catalog:上次起草失败的表打开后的说明(原因和「重新起草这张表」)也截一张图;check-all 的耗时表里数据目录一项按实测改成 110 秒(起草改成后台任务后多了五段检查,单独隔离跑约 108 秒) 2026-10-13 15:32:00 +08:00
ThearchyHelios 31caf02323 设置页加「起草模型」一节(前端):数据目录的「用模型起草」和按配方导入表格时的 AI 起草用的模型,接入、模型两项照核查模型的做法——两项都留空跟随助手的模型,只填模型时写明按模型名用哪个接入,存着的接入不存在、已停用时在那一格下面说清用模型起草会报错,换接入时清掉不属于它的模型;和其余设置共用保存条,改了才整组写 catalog_draft(空着的存 null),服务端按项拒收(422,field 为 catalog_draft.provider)时整句落到那一格、焦点移过去;老服务端没有这一组时不显示。check-manage 加一节覆盖 2026-10-13 15:25:27 +08:00
ThearchyHelios 90a560d07e 数据目录起草改成后台任务(前端):对话框选范围、写起草要求和本次补充说明后建任务,之后显示任务的进度和结果——总进度、新增 / 更新 / 删除合计、逐表状态、宽表的段进度、没写全的原因;可以停止、在后台继续,关掉对话框任务照常进行,目录页上方显示一条进度,点开回到对话框,结束时提示并可查看结果;结果里只列没写全的表,「只重试失败的表」新建只含失败、部分完成、已停止的表的任务;服务重启中断的任务写明原因、同样能重试;已有任务(409)转去显示进行中的那一个,起草模型用不了(409)留在设置阶段写明原因;起草要求改过先存再建任务,写明用的是哪个起草模型、数据源说明也一并交给模型;清单上标出上次起草失败、部分完成的表并写原因,表详情里给「重新起草这张表」;进行中每 1.5 秒取一次,取回的状态只往前走。check-catalog 用假的任务接口覆盖这些(任务怎么往前走由检查自己推),旧的同步起草检查换掉 2026-10-13 15:24:57 +08:00
ThearchyHelios 49583b273f check-all:报告导出的检查加进 ORDER——以前只在耗时表里登记,check-all 不认、一直没跑,README 里写的 28 项这才对得上;那一段的注释改成「复核套件与导出」(占位早就换成了真检查) 2026-10-13 10:20:47 +08:00
ThearchyHelios 06b2c2b8ae 合入报告导出为自包含 HTML(数字点得开口径、来源、计算方式)与可验证报告数字详情里的口径卡一节;和可验证报告的遮罩改造合并:口径卡只给 id 的规则(有指标的值取自遮罩列、文档里写成「已遮罩」的)照旧,随文件附带的卡才附上它的输入指向的查询快照;数字详情保留显示文字核对和超过 2^53 的数照 JSON 原文显示,口径卡一节里输入的值同样照原文;样本页从 16 份变成 17 份 2026-10-13 10:03:24 +08:00
ThearchyHelios 23f9453409 check-verify:设置页「核查」一节存完之后取今日花费的那次请求,满并行时晚于「已保存」到达,轮询等它(最多 3 秒)再判;单独跑一直通过,check-all 满并行时偶发 2 → 2 2026-10-12 23:23:01 +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 7cec3079f0 合入期 5 验收修复 M2:证据面板与推演按 SQL 认出改了名字的遮罩列;推演里取自遮罩格的指标不露原值;报告自查拦下引用遮罩列的格子(按列名对整个数据源生效,和证据面板同一个口径);结论句裁判的摘录按快照逐份遮确定取自遮罩列的列;片段接口在没开结论句裁判时照实说;遮罩分析按快照工件 id 缓存 2026-10-12 14:17:45 +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 ce36aabe92 合入期 5 验收修复 M3:可验证报告核对正文显示的文字与引用的值一致——文字取值逐字比对,数字按服务端的显示规则(千分位、小数位、百分数、万 / 亿换算、单位)核对,认不出的格式判无法核对而不是通过;紧挨数字的不可见字符、缩进挤出屏幕的列表一并判不通过 2026-10-12 11:42:06 +08:00
ThearchyHelios 9344cb9232 M3 复核修正(第 2 轮):紧挨着核对过的数字的字按码点分类收紧,列表缩进有上限、表格只排有格的列
复核发现「紧挨着」只认一部分字:隔着 DEL、U+FFF0 这类显示时不占位置的字补一位数,或者前面加一个 U+2010 这类和负号
长得一样的横线,读的人看到的数已经变了,页面仍「全部通过」;伪造的列表缩进写成十万级,核对通过的数字被挤出屏幕仍判
通过。

- 紧挨着的字按码点分几类(kindOf):数字;负号(横线类标点全算、波浪形的除外,减号类符号,Unicode 易混字符表里映射到
  「-」「ー」的字,在 Chrome 常用字体里逐个画出来是一道横线的字);分隔(半角逗号、句点和易混字符表里长得一样的窄标点,
  全角的不算);不占位置的格式字符、默认不显示的字、变体选择符照旧跳过;控制字符(制表、换行等空白除外)、未分配和私用
  区的字、孤立的代理项、组合附加符号、可选连字符、发丝空格、对象替换符和在 Chrome 里量出来几乎不占宽度的几个字算「说不
  准」:隔着它们照样往外找数字、负号,找不到的也判无法核对、原因另写。只跳过不标记的话,叠在空格上的组合横线、Chrome
  画成短横的 C1 控制字符照样能在数字前面显示出一个「负号」
- 同一句里有从右往左书写的文字(希伯来文、阿拉伯文这类)和方向控制字符一样判无法核对:Chrome 里实测,一个希伯来字母
  就能把逻辑上在数字后面的「5」显示到数字紧前面(读作 574,613.65元),按字的先后看不出来
- 代理对只在真成对时拼成一个字:不成对的前半不再把后面的「1」吞进去;分在两个文字片段里的一对页面上照样显示成数学字母
  区的数字,也拼起来看
- 列表缩进最多显示 8 级,负数按 0 级:十万级的缩进把数字挤到 140 万像素以外,负的连滚动都滚不到;表格只排有格的列:列号
  写成十万时不再建几十万个空格、把那一格挤到右边,写成 2^32 时整段核对也不再出错。核对和显示共用 listItems / tableCells
- 真数据(两份数据目录里 39 份报告文档、1591 处数字和取值、45 个列表、70 张表格)里新旧规则都一处没有触发
- 测试:test_bundle_shown.py 补 DEL、U+FFF0、U+2010、U+2013 等紧挨着的写法,说不准的字、从右往左的文字、缩进和列号的
  用例,逐项去掉实现都会变红;check-bundle 在经营月报上补四种紧挨着的伪造(从右往左那条先量出「5」确实显示在数字紧前
  面),缩进写成十万级和负数(宽屏、窄屏)、表格列号写成十万的伪造
2026-10-12 10:52:09 +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 6d4f452f36 M4 复核修正:规范化后不同的行带上所在的子句,ON 挂在 JOIN 那一行的末尾
复核发现上一版把 ON 单独排成一行后,「规范化后不同的行」丢了关联条件的上下文:只差一个关联条件时那一栏只剩
「AND refunds.state = 'done'」,有两个 LEFT JOIN 时看不出是哪个 JOIN 的,也看不出是关联条件还是筛选条件;两边 JOIN
的表不同时,两边都有的那一行「ON」被 difflib 当成相同的行吃掉,表名下面直接跟条件;关联子查询换成两张表时也一样。
这几种都只给兜底说明,审核人全靠这一栏逐行对照。

- sql_semantics:ON 挂在 JOIN 那一行的末尾(表名、子查询的右括号后面),条件各占一行缩在下面,仍比 WHERE 的条件
  深一级(ON 里和 WHERE 里的同一个条件不当成同一行)。text_diff 里不同的行前面带上它的各级上级行(排在前面、缩进比
  它浅的最近一行,一层层数到顶格),以「  」开头、两边相同,只为标出不同的行在哪个 WHERE、哪个 JOIN 的 ON、哪层
  子查询里;截到 40 行时末尾落单的上级行不留。只动排版:拿测试里的 SQL 语料(990 对,4 种方言、有无表结构、两个
  方向)逐对比过,equivalent、items、fallback、level 和改之前完全一致,有没有不同的行也一致,不再有单独一行的 ON。
- SqlDiff 的约定多一条:「  」开头的是上下文行,只跟着不同的行出现。test_sql_semantics 的 check_shape 原来只认
  「- 」「+ 」,改成也认「  」、并要求最后一行是不同的行(374 个用例只因这一行断言变红,判定和说明都没变)。
- 审批卡(DualCheckApproval):两栏各自只放用得着的上级行(这一边不同的行往上数,缩进更浅的最近一行,一层层往上),
  只有另一边用得着的不放;上级行不高亮、用淡一级的字色(同原文栏里没标的行),标题后面说明「淡色的行两边相同,标出
  所在的子句」,悬停也是这句;这一边没有不同的行时照旧说没有,老工件没有上级行,照旧。lineDiff 注释里「条件并成
  一行」的旧说法改正。
- 测试:test_sql_text_diff 里 ON 那条的期望改成带 JOIN 的上级行,补两个 LEFT JOIN 只差一个关联条件(两个方向)、
  两边 JOIN 的表不同、关联子查询换成两张表、同一个条件在 ON 和 WHERE 里、顶格的行不带上下文、40 行截断几条;去掉
  上级行、去掉「ON 挂在行末」、去掉截断后的清理,各自让对应的用例变红。
- 夹具 dual_check.json 按 test_dual_check_fixture 的办法重新生成(只变 text_diff),另加 join_condition 变体(只差
  一个关联条件、只给兜底);check-verify 查两栏的上级行(WHERE)列在不同的行前面、不高亮、标题有说明,join_condition
  下原流程一栏是带 ON 的 JOIN 加缩进的条件、盲算一栏不画只有原流程用得着的上级行,深浅色对比度、390px 不溢出。
2026-10-07 01:34:59 +08:00
ThearchyHelios ab2173c665 M3 复核修正(第 1 轮):单位带尾随空白的真报告不再被判不通过;运行输入也核对显示文字;出处面板的长整数一位不差;核对通过的字要原样显示在正文里
- 显示文字比对两边都只去首尾空白:口径卡单位写成「元 」(单位输入框不去空白、指标节点照存)时,服务端照原样接在数
  后面,正文是「74,613.65元 」。以前只去正文一边,原样导出的真报告被判不通过,出处面板里两行字看起来一模一样,读者
  会以为文件被改过
- 运行输入([[i:…]])不随文件附带,照旧无法核对;正文显示的字拿引用的值按服务端的写法(不分组、不接单位、可带换算)
  重新渲染比对,只改显示文字(统计周期、地区这类)的判不通过
- 出处面板:DECIMAL 落成数字文本的格子,「快照里的值」照快照原文写;快照那一行的数照 JSON 原文写。超过 2^53 的订单号
  不再在「通过」的条目里和一位不差的「引用的值」并排、自相矛盾
- 正文的排法核对和显示共用一套函数(unitPlan / flowsOf / checkLayout),读的人看到的数要就是核对过的那个:伪造的链接
  把数字塞进不显示的链接地址时,整句按未排版的原文显示;正文里根本不显示的(分隔线里、表格行列之外的格)服务端导出时
  不会出现,判不通过;紧挨着补数字、负号(隔着零宽字符、显示时藏起来的排版标记也算)或同一句里有方向控制字符的判无法
  核对,两个数之间的区间连字符照常通过。正文按片段本身找核对结果:文字片段冒用数字的 id 借不到「通过」(以前会显示成
  绿色下划线的可点数字)。真数据 71 份报告文档、3266 处已解析的数字和取值里,新规则一处都没有触发
- 「无法核对显示文字」的几条原因改成读者看得懂、知道怎么办的说法,不再提 BigInt、正则、ASCII
- check-bundle:真导出上断言没有「无法核对显示文字」(显示规则漏了真实写法时这里先报);订单号连同快照那一行一位不差;
  新样本页 formats-unit(单位带尾随空白,原样导出全部通过);经营月报上链接藏数、补一位数、整段改成分隔线、文字片段冒用
  数字的 id 四种伪造各自断言
2026-10-07 01:34:32 +08:00
ThearchyHelios 3e0aacac18 M2 时间线认得报告引用了遮罩列的那一行:decode.ts 把日志 report_masked_cell 说成「报告引用了 N 处取自遮罩列的格子,已标注」,副标题点名引用(不写值),下一步说出具已降档、去改写作指令;证据面板的违规清单给 masked_cell 一个自己的叫法「引用了遮罩列」,不再落成「文档核对未通过」
文案放在 terms.ts 新块 MASKED_CELL_TEXT;check-decode.mjs 加一节守住后端字段(count、refs、columns)、标题、副标题、缺字段时的说法。
2026-10-07 00:24:19 +08:00
ThearchyHelios 056c782af7 M3 check-bundle 收尾:伪造的辅助函数不再交回用不到的改前文字 2026-10-07 00:23:24 +08:00
ThearchyHelios 6ff9d7155b M3 可验证报告核对正文显示的字:按服务端的显示规则把引用的值重新渲染、逐字比对
验收发现:页面只核「引用的值 = 口径卡的值或快照的格子」,不核正文显示的字。只改显示文字(74,613.65元 改成
84,613.65元、华南改成华东)、引用值不动、重算全部哈希的伪造页照样「全部通过」,读者看到的数和核过的数不是同一个。

- verifier.js 移植 engine/evidence.py 的 render_number / render_cell:千分位、不分组、小数位(含负数位)、比率显示成
  百分数、万 / 亿换算、pct、int、.N、单位后缀、负数、0,文字压成一行(按 Python 的空白),竖线换成 ¦,ISO 日期时间按
  文档记下的单元格显示规则版本。数照 Python 的 Decimal 算:系数用 BigInt,ROUND_HALF_UP,浮点取最短写法,整数取 JSON
  原文(新写的 numberTokens 读出每个数的原文,超过 2^53 的订单号一位不差)
- ⑤ 在引用的值对上之后再核显示文字(只去掉首尾空白):对不上判不通过,原因点名「正文显示「X」,引用的值是「Y」」,
  数字另写按显示规则应显示的字;渲染不出来的(不认识的换算、显示规则版本、对象和列表、非 ASCII 数字、缺 BigInt 的
  浏览器)判「无法核对显示文字」,不判通过。出处面板改成列出按显示规则应为的字,一致时注明,页脚说明同步
- 在 node 里载入时(没有 document)交出核对用的纯函数,tests/test_bundle_shown.py 拿服务端的渲染逐条对照约八万个
  组合,并在 node 里整份核对:经营月报样本每种格式原样通过,只改显示文字的伪造逐个变红并点名
- 样本页加经营月报(formats);check-bundle 在真导出上只改一个数字(有文字取值时也改一个)的显示文字,在经营月报上
  改文字取值、数字、换算成万的口径卡引用,各自变红并点名,原样导出照旧全绿
2026-10-07 00:17:22 +08:00
ThearchyHelios 5b18eab310 M4:双盲复算「规范化后不同的行」每个条件一行,两边相同的条件不再被标成差异
验收时审批卡把两边完全相同的日期区间标成了差异:_text_diff 逐行比两边 sqlglot pretty 的输出,pretty 按宽度决定
换不换行,两个合取的 WHERE 排成一行、三个的拆成三行,同一个条件在两边落在不同的行上。原文 SQL 都是单行时原文栏
一行都不标,这一栏是唯一逐行指出差在哪的地方,审核人会以为统计期也不一样。

现在逐行比之前两边按同一套排版写(_diff_lines / _line_generator,按方言给 sqlglot 的生成器加一处改动):WHERE、
HAVING、ON 的合取式每个条件一行,各层子查询里的也一样;条件本身是 OR 连起来的一律加括号(单独一个和与别的并列时
写法一样);ON 照 WHERE 的样子单独一行、条件缩进在下面(ON 里和 WHERE 里的同一个条件不当成同一行)。比的时候
不看条件前面的 AND(一边多出来的条件排在最前面时,另一边同一个条件只差在有没有 AND),列出来的仍是各自原样的行。
只动排版:判不判等价、差异说明不变(拿测试里的 SQL 对照语料按三种方言、有无表结构逐对比过,items、equivalent、
fallback、level 全部一致),sql_semantics、sql_equivalence 原有测试全过。

前端夹具 dual_check.json 里的 text_diff 是服务端的真实输出,按 test_dual_check_fixture 的办法重新生成(只变了
text_diff);check-verify 的对照行一节另查「只差结束日期时开始日期不标」「多出的两个条件各占一行」。
2026-10-07 00:12:31 +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 c1e1fcddfe 合入期 5 前置修复 L2:可验证报告里设了遮罩的数据源上、能证明没取遮罩列的查询快照照常随文件附带,引用它的数字可以核对;解析不了、可能展开出遮罩列、整行引用的照旧只给哈希,说明写清原因 2026-10-06 22:19:34 +08:00
ThearchyHelios 39b4b6d608 合入期 5 前置修复 L1:上传表格建的数据源按导入配方里的逻辑类型认日期列,双盲复算的选择能写成业务日期;报告的结论句策略要求核对、正文却写在代码块里(结论句为 0)时,出口契约记一条缺口、不再判完整出具;compose_doc 的说明照实写 source 来自调用方 2026-10-06 22:19:34 +08:00
ThearchyHelios b4edcadc88 合入期 5 前置修复 L3:记录页的工件列表把双盲复算对照、反方审稿记录、质询回答归到「核查记录」一组,窄屏下说明换到第二行、序号不被截掉;运行对比的默认基准接口带上 previous,运行详情的对比入口在基准不是紧挨着的上一次时写明「与上一次成功的运行对比」,和触发历史一致 2026-10-06 22:19:25 +08:00
ThearchyHelios 0580663f6e 助手栏连着选两次、两次都没存上时退回服务端存着的设定:以前退回的是第一次选时显示的乐观值(从没存上),原因和齿轮红点一起消失;现在记下服务端最后一次认下的设定,没存上时退回它并再取一次以服务端为准。check-studio 用放行闸门造出先发的那次还没回来就又选了一次的情形 2026-10-06 20:10:51 +08:00
ThearchyHelios db84e576c0 模型接入报错收尾(第 1 轮复核,前端):反方审稿的模型一栏不再多出一句相反的说明;检查器读工作流默认设置里的模型;助手栏保存失败时退回原样并说明、「当前」只写在跟随默认上、原因的去向写「上方」;接入「启用」的说明另起一行;落到演示模型的修复候选加醒目标签
- 检查器:模型一栏的留空说明(modelDefault)只用于节点定义里的模型栏。反方审稿的「反方模型」自己画、只读节点自己的
  配置、留空跟随设置,以前全图默认点名了接入时也被套上「留空则使用接入「X」的默认模型」,和它自己的说明相反;工作流
  默认设置写了模型时,空选项和说明写「使用工作流默认设置的模型「X」」(后端执行时取的就是它,也不报「没有指定模型」),
  不再说成某个接入的默认模型;
- 助手栏「助手使用的模型」:重新选择时保存失败,下拉、原因、齿轮上的红点退回选之前的样子(服务端存着的没变),下面写
  「保存失败,助手使用的模型未更改」,收起再展开后不再留着;只认最后一次选择的回包;选了具体模型时「跟随默认」不写
  「当前」(那时服务端给的 effective_model 是选的那个模型);下拉下面的原因用服务端的 panel_error;
- 设置页接入编辑框:停用的后果另起一行写在复选框下面(aria-describedby 接上,读屏名只是「启用」),不再和「启用」并排
  放在 label 里把它挤成上下两个字;说法收紧为「停用后,该接入的模型不再出现在下拉列表中,指定它或其模型的节点和设置也
  无法调用」——调不了以后怎样(报错、转人工审批、记未裁判、记缺口)由各组自己那句说,不笼统写「运行时报错」;
- 发布前检查:候选带 demo 标记时,选项名旁加提醒色的「演示模型」标签,说明里那半句照旧(normalizeFix 留下这个标记)。
  types.ts 的 PublishFix 选项加可选的 demo 字段。

检查:check-studio 那一节加反方审稿不套说明(全图默认点名接入、写了模型两种)、工作流默认设置带模型时的空选项和说明、
保存失败退回原样与收起再展开、选具体模型不写「当前」、原因写「上方」;check-manage 量「启用」只占一行(1440、390)、
说明不在 label 里、读屏名只是「启用」、说明在弹窗里;check-publish 的伪造门禁跟上「无法改用其他接入:」与 demo 标记,
加一节演示标签(两个候选各一个、提醒色而非淡色、和选项名同一行、390 宽在弹窗里)。新加的检查项对着改动前的界面跑过,
都会不通过。
2026-10-06 19:43:44 +08:00
ThearchyHelios 8c0c3b8eeb 可验证报告复核修复:遮罩源上的查询快照再堵几条带出号码的路,口径卡和快照按同一个结论判
复核查出,上一轮放开「没碰遮罩列的快照照常附带」之后,有几种写法 SQL 里不写 phone、结果列名也对不上,结果里照样是
号码,快照原字节和查询事件的预览会随文件附带出去。这一轮逐条堵上:

- 整行引用认全(复核的两个阻断项):Postgres 的 FROM 里的表函数不写 LATERAL 也看得见前面的来源,
  `FROM members m, jsonb_each_text(to_jsonb(m))` 这类逐列画像的写法(逗号、CROSS JOIN、JOIN … ON TRUE、LEFT JOIN、
  ROWS FROM、不带别名的 UNNEST、套在 FROM 的子查询里)以前按看不见算,整行引用认不出。现在 FROM、JOIN 里只有真的
  子查询和 WITH 里的一段看不见同一层;括号括起来的一组连接((members m CROSS JOIN f(m)))也摊开按同一层认。另外认
  函数记法 m.to_jsonb、m.row_to_json(等于 to_jsonb(m)),自己建的函数认不出。
- 不点列名也读得出表里内容的写法(_INDIRECT_READS):SQL、表名写在字符串里交给函数执行或整表导出(table_to_xml、
  query_to_xml 一族、ts_stat、crosstab、DBMS_XMLGEN、XQuery 的 ora:view),统计信息里的采样值(pg_stats、
  sqlite_stat4、column_statistics、Oracle 的直方图和 *_tab_columns),按页按文件读的原始数据(get_raw_page、
  pg_read_file、LOAD_FILE、sqlite_dbpage、逻辑解码),别的会话的 SQL 原文(pg_stat_activity、general_log、V$SQL),
  系统 schema(pg_catalog、information_schema、performance_schema)。SQL 原文里出现就只给哈希;函数名要跟着左括号,
  列名碰巧叫 crosstab、pg_status 的不受影响。
- 这次运行里查到过的遮罩值写进了别的查询的字面量(模型拿看到的号码去查别的表):导出时收齐封存范围内每份快照里
  取自遮罩列的格子(inquiry._Secrets 的按值认得出的写法),只看 SQL 的字面量,碰上就只给哈希、查询事件也只给哈希。
  这次运行里没查到过的值(提问人写进问题的)认不出。
- MariaDB 会执行的注释 /*M! … */ 和 /*! … */ 一样按语法树认不准处理。
- 口径卡和快照按同一个结论判:快照因列名表、整行引用、不照原名展开的 *(UNION 一支里按位置对上列名的、装进一列
  的)、吃进遮罩列的表函数、语法树认不准或不点列名也读得出内容而只给哈希时,卡上取自这份快照任一列的输入都按遮罩列
  算,整张卡只给 id。以前卡这条路只认改了名字的遮罩列,快照只给哈希,卡上记着的号码却原样进了文件。最外层直接写的 *
  照原名展开,按名字认就够,卡照常嵌入。
- check-bundle 的 masked-source 样本点数字之前先看有没有核对通过的数字,没有就记一项不通过、不去点:以前点空了要
  等满 30 秒抛错,同一节后面的 nan、stray 样本都不跑了。换回改动前的 build.py 实测,现在只多记两项不通过,后面照常跑。

有意没改的一条:SQL 写到遮罩列、结果里却没有号码的(COUNT(DISTINCT phone)、phone IS NOT NULL)照旧只给哈希,比规格
的四条更严。FROM 里的表函数吃进遮罩列时(unnest(ARRAY[phone]))它交出的列取自哪一列认不出,只能看 SQL 写没写到;
补了这一例的测试,说明写在 _untouched 和测试里。

测试:新增整行引用(表函数、括号里的一组连接、函数记法)、不点列名的读法、字面量里的遮罩值、MariaDB 注释、口径卡
七种认不出来历的写法各自的用例,以及对照组(列名像函数名的、表函数只吃没设遮罩的列的、括号连接按名字取列的、最外层
* 的卡)。合并查询那一条判断补了只带认得的键的夹具,结果列名那一条补了按 SQL 认遮罩列的那一套什么都没认出来时的
用例,两条现在都能单独证明——上一轮提交说明里「每一条规则都做过去掉实现测试变红」对这两条不成立。这一轮 15 处改动
逐一去掉实现,相关测试都变红。
2026-10-06 18:33:02 +08:00
ThearchyHelios 53bb356fae 复核第 1 轮:对比入口预先问默认基准带 5 秒超时、问到没有默认基准时写「选择基准对比…」直接去对比页手动选、切回页面时再问一次;工件页签的悬停照实写,320px 时校验值和大小不再拆开
- 对比入口(pages/runs/compare/entry.tsx):预先问 compare/base 卡着不回时 5 秒后按没问到算,叫法退回「与上一次对比」、可点,不再一直停在不可点的「正在查找」;问到没有默认基准(多为工作流的第一次运行)时写「选择基准对比…」,点了直接去只带本次的对比页手动选(对比页自己再找一次),不再写「与上一次对比」、点了再问一遍弹提示;切去别的标签页再切回来时再问一次,问的期间保留原来的叫法、可点,问到不一样才换,问不到不改;更正预先问那段注释的前提(compare/base 不回 409、422,不先问是因为这些入口本来不给点)
- 运行详情「工件」页签头的悬停写上证据快照、核查记录和每个节点的产出三组(RUN_ARTIFACTS_TEXT.tabTitle,RunDetailView 只换这一处);证据快照的悬停不再说「结论里的数字从这里来」,点明含核查、质询时执行的查询;核查记录的悬停用行上的种类名,指明其间执行的查询见「证据快照」;两句都在 45 字内
- 工件行的校验值和大小包在一起排、一起折行,这一栏窄于 22rem 时收起校验值:320px 下大小不再单独折到种类下面,每行仍是两行
- 对比页没带运行时的说明缩成 32 字,不逐个列菜单项的叫法
- 检查:check-compare 补预先问超时、没有默认基准、切回页面再问、点了才发现没有基准后叫法跟着改、工件页签悬停几节;check-verify 改两组悬停的断言、补 320px;check-schedules 的假 compare/base 补上 previous: false(和服务端一致),断言运行详情菜单项与触发历史链接的叫法一字不差
2026-10-06 18:25:35 +08:00
ThearchyHelios 0bf2f8ba63 check-studio:助手栏那一节的伪造设定改成接入连同一个列得出的模型,「下拉停在存着的设定上」「发出的请求不带模型」两项才分得出新旧写法(Playwright 的 selectOption 选同一个值也会触发 change,单靠「重新选跟随默认」分不出来) 2026-10-06 18:10:15 +08:00
ThearchyHelios b7da8a9af9 出口契约认藏在代码块里的正文:只挂 [[see:]] 依据的、不带句读的列表项也认,代码里的注释和字符串不算句子,英文句子改成线性扫描
上一轮只看片段里的引用和带全角句读的行,几种写法仍会让正文藏在代码块里照样完整出具,另有几种代码被当成正文:
- [[see:]] 记在句子的 see 上、不在片段里:只用 see 挂依据的列表现在也认
- 中文报告的列表项常不带句读:以 - * + • 或「1.」「1)」开头、后面有两个以上汉字的行算成句;信息串为空、看得出是
  SQL / Python 的块里(有 SELECT、FROM、def、import 这类开头的行),以 * + - 开头的是运算的续行,不当列表项
- 信息串写成 plaintext、txt、plain 的和 text 一样算写文字的代码块
- 判句之前去掉字符串字面量(可带 f、r、b、u、N 前缀;英文的 it's 这类不动)和行尾注释(-- // #),# 开头的行、
  跨行的 /* … */ 块注释都不算:SQL 行尾的中文注释、print 里带全角标点的字符串不再让 0 句的报告降档
- 认英文句子的正则对很长、不带句末标点的一行是平方级回溯(出口复核在事件循环上同步执行),改成按词串逐个数单词,
  耗时随行长线性增长

check-decode 补一项:从 io.py 读出 GAP_FENCED_BODY,钉住它归「校验不完整」、不进核查的两组。补参数化用例和端到端
用例:只挂 see 的列表、不带句读的列表、plaintext 包住正文的正式运行降档并带这条缺口;带行尾注释的 SQL 照常完整出具;
四万多字的长行一秒内判完。
2026-10-06 18:03:12 +08:00
ThearchyHelios c8800d75e3 模型接入报错的说法与修复候选收尾(前端):助手栏照实显示存着的模型设定、能重新选「跟随默认」清掉失效的接入;检查器模型一栏说清留空用哪个接入;停用接入的后果写全;问题只认自己那一处的修复
- 助手栏「助手使用的模型」:读 GET /api/copilot/model 的 error,照实写在下拉下面,齿轮上加红点(收着时也看得出来)。存着的
  设定下拉里列不出来(点名了接入,或模型不在可选列表中)时列成一项并选中,不再停在「跟随默认」——以前看着一切正常、
  发出一句话才报错,而且再选「跟随默认」不算改动、清不掉存着的接入,报错又指到改不了它的设置页。这时发出的请求不带
  模型,服务端按存着的整组取,和下拉上显示的一致;
- 检查器模型一栏:节点(没写就是全图默认)点名了接入时,空选项和说明写「使用接入「X」的默认模型」;X 不存在、已停用时
  空选项说状态、不写说明,不再和检查器顶上接入那条问题矛盾(同后端去掉「没有指定模型」那一条);
- 设置页:接入编辑框「启用」旁、卡片上「已停用」的悬停说明写全停用的后果(指定它或它的模型的节点和设置运行时报错),
  不只说下拉里看不到;门控、裁判、核查三格存着的接入名恰好是某个启用接入的模型时,补一句在这一组哪一栏用它,和服务端
  保存时 422 的那句一致;
- 发布前检查:点名的模型接入只认节点、字段都对得上的修复,没有就是这一处没有修复,不再退到同节点、同编号别处的修复
  (同后端 annotate)——以前给不出修复的那一行下面会画着另一处的选项;
- 说法收进 terms.ts(PROVIDER_REF_TEXT、ASSISTANT_MODEL_TEXT),getModel / setModel 的返回补上类型(CopilotModel)。

检查:check-studio 加一节(检查器空选项与说明、助手栏的错误与重新选择、发出的请求不带模型、390 宽不多撑出横向溢出),
check-manage 加一节(停用后果、接入名恰好是模型名)并跟上 422 的新说法,check-publish 的伪造门禁照后端「没有修复时
不指到发布前检查」,加一节给不出修复的那一行不借同节点别处的修复。
2026-10-06 17:51:26 +08:00
ThearchyHelios 2a64099cb8 对比页没带运行时的说明把菜单项的两种叫法都写上:上一次没有成功时运行详情的菜单里写的是「与上一次成功的运行对比」,说明只写「与上一次对比」会让人找不到
check-compare 跟着核对两种叫法都在
2026-10-06 17:24:17 +08:00
ThearchyHelios 0f48bd17c4 运行详情「工件」页签:双盲复算对照、反方审稿记录、质询回答单独归到「核查记录」一组;窄屏上说明换到第二行,第几件和第几次尝试在截断范围外,悬停写全说明
分组:以前这三种都算进「证据快照」,那一组的说明却写着「查询、工具调用、知识检索的原始结果」。model.ts 加 artifactGroup(证据快照、核查记录、节点产出三组,按种类分),筛选多一档「核查记录」,件数、悬停说明跟着改:证据快照写上口径卡、报告文档和表结构,核查记录说清装的是什么、核查时执行的查询快照仍归在证据快照。别的种类的归类不变(isEvidence 改成只认证据快照这一组,认不出的种类照旧算证据快照)。口径卡里容器型变量输入的完整值(metric_input)以前露键名,补上名字「指标输入」和说明。

窄屏:以前一行里挤着种类、说明、校验值、大小和时刻,390px 时说明只剩三个字、序号也被截掉。行按列表这一栏的宽度排(容器查询,35rem 以下),窄时说明换到第二行占满整行,第一行留种类、校验值、大小和时刻(时刻和种类对齐);序号和第几次尝试从被截断的说明里挪出来;按钮的悬停写「打开某种工件:整句说明 #n」。容器设在列表上、不设在整个页签上,查看工件的弹窗(fixed 定位)不落进容器里。新文案放在 terms.ts 的 RUN_ARTIFACTS_TEXT。

新预览用例 ?syn=run-artifacts(虚构的门店周报,22 件,各种工件都有,含封存后追加的长问题质询回答)。check-verify:分组和 isEvidence 的口径、四档筛选的件数和悬停、点各档只剩该组;390px 深浅色下说明都在第二行、被截断的说明看得见至少 200px(以前 0 到 63px)、第几件整个落在行内、时刻在第一行和种类对齐、不横向溢出、对比度。check-inquiry:工件页签的读法改成按 data 属性,质询回答归在核查记录、悬停带整句说明
2026-10-06 17:15:52 +08:00
ThearchyHelios 02883dea7b 可验证报告:查询快照只给哈希时照实说明原因,样本页和浏览器检查补「遮罩源上的汇总查询可核对」
核对页对只给哈希的查询快照原来写「含遮罩列,未随文件附带」。现在没碰遮罩列的快照照常附带,只给哈希的是这条查询
用到或可能用到设了遮罩的列(条件里写到的、解析不了的也算),原文改成「这条查询用到或可能用到设了遮罩的列,快照未随
文件附带,只能核对到哈希」;口径卡的说法不变。核对逻辑不变,只是按工件种类挑说法(verifier.js 的 maskedQuery);
内联脚本的 CSP 哈希由 render_html 按脚本现算,不用另改。顺手改正 verifier.js 开头一句过时的注释:口径卡现在会因遮罩
只给哈希,导出时不会出现的是报告文档标着遮罩。

tests/bundle_samples.py 加样本页 masked-source:会员库设了号码遮罩(查询当时记下了、数据源现在也设着),报告引用会员
按地区汇总的查询和选出了号码的那份。check-bundle 断网打开它:汇总快照在 ③ 通过、引用它的两个数字在 ⑤ 通过、点开看得
到汇总的 SQL 和被引用的那一行;选出了号码的快照和引用它的数字无法核对并写明原因;总览「可核对的项全部通过」,页面里
找不到号码。另在这一页上篡改:汇总快照改一个字节 ③ 变红,改它的数字的引用值并重算全部哈希 ⑤ 变红。base 页上的原因
文案跟着改。test_bundle_build 守住样本页的形状。
2026-10-06 17:11:41 +08:00
ThearchyHelios 50f15b40c4 合入期 5 前置修复 K1:点名的模型接入不存在或已停用时照实报错,不再悄悄换成演示模型——各条用到模型的路径照实失败或记为核查不可用;保存设置时 422、画布校验给警告、发布与发布前检查挡住并给修复候选(不指定模型、改用启用的接入),只写模型而提供它的接入已停用也查得出 2026-10-06 16:55:27 +08:00
ThearchyHelios 6514db6118 运行详情「更多」里的对比入口按默认基准是不是紧挨着的上一次定叫法:上一次失败、取消、还没结束时写「与上一次成功的运行对比」,和定时任务触发历史里的同名链接一字不差、点进去是同一个基准
拿到能对比的运行(已封存、属于已保存的工作流、不在运行中)就预先问一次 compare/base,按答复里的 previous 定叫法;按运行 id 加清单哈希记,失败后接着运行完重新封存了会再问。问到之前这一项只写「正在查找上一次成功的运行…」、不给点:菜单开着时不会先写一个叫法、问到了再换成另一个,也点不到说错了的入口。预先问出错、找不到默认基准都不提示,叫法退回「与上一次对比」,点了照常再问一次、照实说。点了总是再问一次、按那一次的答复跳:详情页可能开了很久,预先问到的基准不一定还是现在的。

类型 RunCompareBase 加 previous(老服务端不给,按 true 算,同 ScheduleFireCompare);两种叫法放在 RUN_COMPARE_TEXT(menu、menuLastOk),SCHEDULE_TEXT 的 compareLinkLastOk 和 compareLink 一样改成取它的 getter,过时的说明一并改掉。check-compare:夹具里本次的默认基准带 previous: false(和触发历史那一行同一个假定);上一次失败了、上一次就是成功的两种,运行详情和触发历史两个入口叫法一致、打开同一对运行;预先问的那一次压住时菜单项只写正在查找、问到后直接是最终叫法(记下菜单开着时出现过的每一种状态核对);预先问出错、找不到基准时不提示、点了照常再问;点了之后对比页不再自己找一遍
2026-10-06 16:52:30 +08:00
ThearchyHelios 0a690a599b 发布前修复点名的模型接入:按执行时的取法算修完落到哪里,只写了模型而接入已停用的也拦下
- 「不指定接入」以前只去掉接入、留下同一处写着的模型,复核又只查点名的接入:按模型名落回停用的接入,或者成员跟随节点、节点跟随全图默认,拿别家的接入去调这个模型。检查、发布都通过,正式运行在那一处照样失败
- 现在每个候选(不指定、改用某个启用的接入)先在副本上改,按执行器的取法(成员先看自己、再看节点、再看全图默认;节点看全图默认;都没写按模型名找;核查和裁判整组交给设置)算出改动波及的每一处用哪个接入、哪个模型。落到的接入不提供那一处的模型、按模型名落到停用接入或认不出的模型、落到内置演示模型的,连同一级写着的模型一并去掉再算,还落不稳的候选不给;候选说明写清执行时改用哪里、模型去没去掉、换上的接入实际用哪个模型
- 门禁把哪一级都没写接入、只写了模型而提供它的接入已停用的那一处也记成 provider.disabled(落在写模型的字段,原因和运行时同一句):复核拒得掉这类修复,检查器里只能选模型的节点发布前也查得出来;这一处配「不指定模型」或改用一个启用接入的修复
- 按模型名找接入、没写时退回哪个接入抽成 factory.provider_for_model、fallback_provider,运行时和门禁共用一份
- 问题面板、修复预览写得出「模型」「成员「x」的模型」;check-publish 的伪造门禁跟上新的候选,补只写模型的一段
- 测试:复核发现的几种形状逐一钉住(含发布前检查修好、保存、发布后正式运行成功的端到端一条);依赖旧做法的两条测试改成新的正确行为
2026-10-06 16:31:06 +08:00