Commit Graph

631 Commits

Author SHA1 Message Date
ThearchyHelios 7bc7fc685f 起草按复核修正:读回复出错也记进用量;补问时列出了、字段留空不算没写出来;留空的列看目录里已有的;一项都没写出来的宽表逐段写范围;提醒照约定的说法
- 读回复时出了意料之外的错:这次调用照样记进用量(算一次出错),再交给 _guarded 记这一块没写出来;以前 _take 抛异常
  时这次调用不进 calls、token、failed_calls,也不进提醒的窗口。校验(catalog._from_model)里该是文字的地方写成了
  数组、对象的(列名、表类型、业务日期的列、度量类型,columns 不是数组的)直接丢掉、不抛异常:实测列名写成数组时
  抛 TypeError,整张表记「起草这张表时出错」。
- 补问时请写的列都列出来了、字段留空:表上算拿不准(记留空),用量和提醒里也不再算一次「只给空壳」没写出来;以前
  提醒会因此劝人换模型,真正该做的是补充起草要求。
- 留空的列不算目录里已经有中文名或含义的(不论来源:以前模型起草、按「重新起草不丢内容」留下的,库注释,人工;驳回
  的不算有);写入时(write_draft)再按并入目录之后的结果筛一遍,起草进行中有人填了的同样不算。以前照界面的建议补了
  起草要求再起草,模型这次没再给的老列又被说成「拿不准、留空了」,提示一直消不掉。
- 一项都没写出来的宽表同样逐段写上列的范围:「这张表 95 列,分 4 段起草,第 1 段(表级的项)、第 2 段(c001 到
  c032,共 32 列)……都没写出来:原因」;只有一段的表照旧只写原因(这一段就是整张表)。
- 提醒照约定写「建议在「设置 → 偏好设置」的「起草模型」换一个模型、缩小起草范围,或者停止这次起草」。
2026-10-13 21:25:59 +08:00
ThearchyHelios 84405977b6 起草引擎按复核修正:每个原始段连同分开的各块一共 8 次;一直超时的模型几轮就停;止损后纯文本不再原样再问
- 封顶管到原始段:段大小减半以后,新开始的段按上限分开的各块(窄表重新拼成的各组、单表均分的各块)共用这一段的
  调用次数(_Budget 在 _work 里按原始段建,_start、_guarded 接过去),不再每块各有 8 次。以前上限缩到 10 列后一直
  只给空壳,4 张窄表拼成的 40 列段调用 20 次,最坏是「段列数 / 上限 × 8」。止损的计数(连续几段没写出来)同样按
  原始段数。
- 超时的两半同时问:带表级项的前一半不再先写完才问后一半(一次超时就是一个时限,40 → 20 → 10 串着问要好几个时限);
  额度用完、只给空壳的照旧先写前一半、后一半拿它做背景。
- 超时另有一条止损:拆到每段 10 列(MODEL_MIN_PART_COLUMNS)的调用接连超时 2 次(MODEL_GIVE_UP_AFTER),超时就和
  段大小无关了,后面超时的不再拆小,超时拆出来、等名额时还没问的块也不再问(次数退回);有一次调用写出来就恢复。
  只管超时:额度用完、只给空壳照旧拆小。原因后面补「拆到每段 10 列仍然超时,已停止拆小重试,建议更换起草模型」。
  用假模型量:每次都超时的 40 列表从 8 次调用、约 7 轮(420 秒时约 49 分钟)降到 6 次、3 轮;首轮同时起草的 3 段从
  24 次、约 8 轮降到 12 次、4 轮;40、20 列超时而 10 列写得完的照旧拆到 10 列全部写出。
- 止损以后本来能拆小的段只给空壳:已经走纯文本的不再原样再问(约定只对拆不开的段再问一次);结构化输出的照旧换
  纯文本问一次。
- resolve_draft_model 的说明照实写:超时不由引擎重试,当作这一段太大、拆小再问。
- 止损的说明改成文字(_Why.halted),两种止损各说一次。
2026-10-13 21:25:27 +08:00
ThearchyHelios 1e1aa3f64a 起草引擎:提醒第一次出现时记一条日志(最近几次调用有几次没写出来、原因);模块说明补上补问时才列出、字段留空的列也算拿不准 2026-10-13 20:30:02 +08:00
ThearchyHelios a9170d8728 README:数据目录的模型起草补上验收后的修正(列分段均分、按表先后排队、超时拆小、段大小减半、每段 8 次封顶、提醒换模型、重新起草不删模型这次没给的项、留空的列逐表记下、库注释就是名字本身的不当中文名) 2026-10-13 20:30:02 +08:00
ThearchyHelios afc98d1318 旧的同步起草 POST /catalog/draft:同一个源有排队或进行中的后台起草任务时回 409 catalog_draft_busy(和建任务同一句话),不再两边同时写同一个源的目录、抢模型名额 2026-10-13 20:30:02 +08:00
ThearchyHelios 975dde1146 起草引擎按验收修正:列分段均分、超时拆小、段大小随模型减半、每段 8 次封顶、提醒、超时与没写出来的计数、模型留空的列、不插队、原因写清哪几段哪几列
- 均分:超过 40 列的表,列分段数是列数除以 40 向上取整,各段列数平均(相差不超过 1),不再留下 2 到 8 列的尾段(实测
  会思考的模型常对这种小段只给空壳);表级那段、窄表拼段、parts_total 不变。
- 拆不开的段(不到 10 列)只给空壳:再问一次,结构化输出换纯文本,已经走纯文本的原样再问,仍是空壳才记没写出来。
- 超时当作这一段太大:不再原样重试同样大小的段,按额度用完的办法拆小再问;网络错误、429、5xx 仍原样退避重试。
- 段大小随模型调整:一次起草里额度用完或超时累计 2 次,之后新开始的段列数上限减半(40 → 20 → 10,最低 10),新开始
  的段超过上限就先按上限均分开(多表的段按表重新拼);任务记当前的上限 part_columns。
- 封顶:一段(连同它拆出来的、补问的、重试的)最多调用 8 次,到了次数还没写完的记没写出来、原因写清。止损照旧。
- 提醒:最近 6 次调用有 4 次以上没写出来(额度用完、超时、空壳、出错),任务的 notice 写一句提醒(次数、原因,建议在
  「设置 → 偏好设置」的「起草模型」换一个模型、减少表或停止);之后最近 6 次里少于 2 次就清掉。
- 用量:进度回调 usage 换成 call_done(CallReport:用量、没写出来的原因种类、当前的提醒和列数上限),任务的用量加
  timeouts、failed_calls;超时的调用 token 照实记 0。
- 留空的列:请模型写了、模型也列出了,中文名和含义却都没给(或者给的都没通过校验)的列记在 ModelOutcome.blank,逐表
  记 blank_columns 和最多 5 个列名 blank_sample,任务上是合计,目录清单的 last_draft 也带列数;表的状态不因此变。已确认
  的、库注释已经说清的列不算。补问时把漏的列列出来、字段却留空的,算留空,不再记成「漏了这些列」。
- 公平排队:宽表的表级那段写完,它的列分段排到已经排着的段后面(先来先服务),不再插到队首让窄表一直等。
- 原因:几段因为同一个原因没写出来时说「这几段」,同一段拆出来的几块仍是「这一段」;只有真拆小过才补「已拆小重试仍
  没写出」(截断后只补剩下的不算);每段写上列的范围,例如「第 5 段(列名 到 列名,共 33 列)」,窄表写出是哪几列。
- 库:catalog_draft_jobs 加 timeouts、failed_calls、part_columns、notice,catalog_draft_tasks 加 blank_columns、
  blank_sample,旧库启动时补列(存量回填 0 和空)。假模型加 hang(头几次调用一直不回,用来模拟超时)。
2026-10-13 20:30:02 +08:00
ThearchyHelios 645064fe47 数据目录重新起草不丢内容;库注释就是名字本身或标识符写法的不当中文名
- 合并(merge_notes)只改模型起草这一个来源的「覆盖即删」:模型这次对某一项没给值(留空,或者给的值没通过校验、在
  _from_model 里就丢掉了),以前模型起草的项留着,只有给了合格的新值才替换。只有这一轮完整起草过(covered 含 llm)、
  而这一项说的列已经不在表结构里(列级的项看列名,业务主键、业务日期看它们指着的列)才删;write_draft 把表结构里的
  列名交给合并。注释、外键、命名推断、剖析各自的规矩不变,人工确认、驳回的不动。删除数因此只在真删时才有。
  以前整库重跑一次,模型这次没给的几百项全被删掉,有的表覆盖率从八成多掉到五成,表仍记「已完成」。
- 库注释(comment_role):和表名(列注释和列名)相同(忽略大小写、下划线、连字符、空白,表名带 schema 前缀的也比
  不带前缀的),或者是标识符写法(只有字母、数字、下划线、点,不带空格),不当中文名、也不当说明,不记进目录;交给
  模型的表结构里照旧有这条注释。以前这种注释短、不带句读就当中文名,库注释的级别又高于模型起草,模型起草的中文名
  永远进不了目录。已有目录不另做迁移:起草到那张表时,旧的那条随这一轮的注释删掉,模型起草的中文名就能进来。
2026-10-13 20:30:02 +08:00
ThearchyHelios c5a95c9198 test_masking_tool_boundary:查金额原值之前先去掉哈希——工件 id、快照里记的哈希是随机的十六进制,偶尔碰巧含「1200」,全量并行时偶发失败 2026-10-13 16:59:58 +08:00
ThearchyHelios 950b88a15b README:数据目录一节补上模型起草(后台任务、只重试失败的表、中断不自动续跑、保留思考加大额度、按段起草宽表、起草要求与本次补充说明、起草模型设置) 2026-10-13 16:57:02 +08:00
ThearchyHelios f532c5c130 合入数据目录起草改造(前端):起草对话框改成后台任务(逐表进度与段进度、停止、关掉不停、只重试失败的表、两种 409)、起草要求与本次补充说明、目录页进度与清单上的上次起草失败标记和单表重起草、设置页起草模型;check-catalog、check-manage 随之改写 2026-10-13 16:56:02 +08:00
ThearchyHelios e6edc3a582 合入数据目录起草改造(后端):起草模型设置组 catalog_draft、数据目录与配方 AI 起草共用取模型;新起草引擎保留思考、额度 32768 被拒退回 8192,40 列 / 4 张表分段,宽表表级加列分段,按失败原因拆小、补缺、截断捡回、改走纯文本、退避重试与止损;起草要求进提示词;后台起草任务与 draft-jobs 接口、启动标中断不续跑;目录清单 last_draft、active_job、guidance 2026-10-13 16:56:02 +08:00
ThearchyHelios 38d6f47e67 PUT /catalog/guidance 的请求没写 guidance、或者不是一段文字时回 422 带一句中文说明(同超长时的写法),不再是 pydantic 的英文校验结果;表名恰好叫 guidance 的整份提交照旧 2026-10-13 16:48:46 +08:00
ThearchyHelios 4857c578f6 起草的止损和公平:连续 2 段(MODEL_GIVE_UP_AFTER)拆到底仍一项没写出来,这次起草后面的段不再拆小重试,没写出来就直接记下,原因后面补「模型连续 2 段都没写出来,已停止拆小重试,建议更换起草模型」;有一段写出来就恢复拆小。每次起草同时只起草 3 段(MODEL_CONCURRENCY),一段连同拆小、补缺做完再取下一段,宽表的表级那段写完,它的列分段排到最前面一段一段起草;同时在等全进程名额的调用每次起草最多 3 个,几次起草(不同数据源的任务、同步起草)交替排队,后开始的不再等前一个排着的上百段全部调完。实测一直只给空壳的 294 列宽表从 168 次调用降到 81 次,20 张 120 列的宽表一直用完额度从约 900 次降到 122 次 2026-10-13 16:46:52 +08:00
ThearchyHelios c3105bba4f 起草引擎按失败原因处理的三处修正:结构化输出回了一段说明文字(不是 JSON、也没停在额度上,例如网关接受了 response_format 却没照做)不再因为带着思考就当成额度用完去拆,也不直接判失败,这次起草后面改走纯文本、这一段换纯文本问一次(纯文本另带格式说明);只有停在额度上、或者正文为空而有思考才算额度用完。补问之后整列没列出来的列记没写出来(「模型的回复里漏了这些列,补问一次仍没有给出」),表是 partial、covered 不含 llm,以前起草过的待确认模型项不再被删(以前补问只给空壳也记 ok,还把这一轮没给的旧项删掉);列出了、字段留空的照旧算拿不准;补问时整张表还一项都没有的,照只给空壳的规矩拆小、换纯文本,不直接记失败。几处没写出来的原因按基础原因去重,拆小重试过的在最后补一句,不再出现同一句说两遍。假模型照提示词把请写的列都列出来(字段留空是拿不准),要模拟漏列的传 list_all=False 2026-10-13 16:42:45 +08:00
ThearchyHelios ec6838dc10 起草模型的 SDK 不再自己重试:ModelSpec 加 max_retries,build_chat_model 一直传到 SDK 客户端(Bearer 鉴权换上的 Anthropic 客户端也带上);数据目录起草建的大、小两个模型都是 max_retries=0,429、5xx、网络错误、超时只由起草引擎按失败原因重试(最多 2 次)。以前 openai、anthropic 的 SDK 各自先重试 2 次,叠在引擎的重试上,一段最多发 9 次请求,报错却写「已重试 2 次」,网关限流时还放大流量。不写 max_retries 的调用照 SDK 默认,配方 AI 起草不动 2026-10-13 16:40:07 +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 bf0619a03c 目录清单的 last_draft 改在库里挑:每张表最近一次起草任务里的那一项用窗口函数取,起草进行中清单页反复刷新时不再把最近一百个任务的逐表记录全读出来 2026-10-13 15:38:27 +08:00
ThearchyHelios b988a5ae18 起草引擎和后台任务的几处收紧:提示词要求请写的每一列都列出来(拿不准的字段留空、列不漏),免得模型留空的列再被补问;纯文本那条路的格式示例改用「表类型」「度量类型」占位,不让模型照抄示例值;从正文取 JSON 时依次试多个括号作开头,说明文字里带括号、外面多包一层都认得;用量记在单次调用的时限之外,落库慢了不会把已经回来的调用算成超时;后台任务收尾写库出错只记日志;补上从正文取 JSON、任务开始时模型已用不了(整体 failed)的测试 2026-10-13 15:36:24 +08:00
ThearchyHelios f4ef5919bd 数据目录:正在编辑一张表时,它的「重新起草这张表」先不给点并写明先保存或取消——起草会写进这张表,编辑中的保存就会撞上版本冲突;check-catalog 补一项 2026-10-13 15:34:12 +08:00
ThearchyHelios c1a70ecf38 数据目录起草改成后台任务:新表 catalog_draft_jobs、catalog_draft_tasks 存任务和逐表状态,同一个源同时只有一个排队或进行中的任务(接口先查、部分唯一索引兜底);POST /catalog/draft-jobs 建任务(202),GET /draft-jobs/active、/latest、/{id} 读任务,/cancel 停止(排队的直接停,进行中的停掉正在进行的模型调用,已写进目录的不回滚),/retry 只重试失败、只写出一部分、停止了的表;同源 409 catalog_draft_busy、起草模型用不了 409 catalog_draft_model_unavailable、已结束 409 catalog_draft_finished;每张表一结束就并入目录,进度、计数、用量随时落库;服务启动时把没做完的任务标成中断、不自动续跑,关停时同样;目录清单每行加 last_draft,顶层加 guidance、active_job;数据源级的起草要求存在 options 里,经 PUT /catalog/guidance 维护(最多 2000 字,表名恰好叫 guidance 的整份提交照旧),数据源接口不显示、整份回写 options 时留着,拼连接串时摘掉;本次说明最多 1000 字,任务记下起草要求和本次说明的快照,同步起草也带上数据源的起草要求 2026-10-13 15:33:00 +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 6b1f63a9dc 数据目录模型起草换成分段、按失败原因处理的引擎(data/catalog_draft.py):每次最多 4 张表、40 列,窄表按顺序拼段,宽表拆成「表级一段 + 每 40 列一段」,列分段带着表注释和表级起草结果做背景,最后合并照旧逐项校验;思考和输出用完额度、只给空壳时拆成两半再问(最少 5 列、最多 3 层),拆不开的空壳换纯文本问一次,写出来了后面都走纯文本;被截断的 JSON 先捡回已完整的表和列、只补剩下的;缺了的表和列只补缺的、补一次;服务方嫌额度大时退回 8192、结构化输出不支持时改走纯文本,都管到这次起草结束;网络错误、429、5xx、超时退避重试最多 2 次;单次调用 420 秒;全进程最多 3 个调用同时进行;报错写原因和办法(第几段、共几列没写出来、可以只重试这张表);提示词加上起草要求一段(数据源说明、起草要求、本次说明,规矩在前、冲突以规矩为准)和「思考时不必逐列草拟」;同步起草改用新引擎,写入抽成每张表一结束就能调的 write_draft 2026-10-13 15:19:06 +08:00
ThearchyHelios b940b27e24 起草模型设置:新增设置组 catalog_draft(接入、模型),点名的接入不存在或已停用时保存回 422;数据目录起草和按配方导入的 AI 起草共用一处取模型(起草模型 > 助手的模型 > 默认接入),取自起草模型时报错照实说起草模型那一项;数据目录起草不再关思考,额度 32768,服务方嫌大时退回 8192(之后都用小额度),单次调用时限 420 秒交给 SDK;配方 AI 起草的额度、思考设置不动 2026-10-13 15:00:38 +08:00
ThearchyHelios 49583b273f check-all:报告导出的检查加进 ORDER——以前只在耗时表里登记,check-all 不认、一直没跑,README 里写的 28 项这才对得上;那一段的注释改成「复核套件与导出」(占位早就换成了真检查) 2026-10-13 10:20:47 +08:00
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 4cd5f334a3 合入核查与定时七项新功能:双盲复算(看不到原 SQL 的 agent 按输入重算,不一致时停下来让人选、只差一个条件时把选择写进数据目录,设置可全局开关、节点可单独设)、两次运行的变化三分法(口径变化、数据变化、参数变化,按维度找主要贡献)、反方审稿(关键结论逐句用只读查询去驳,被推翻的让出具降档)、可验证报告(单个文件断网重算哈希、逐个核对数字和显示文字,遮罩快照只给哈希)、审批质询(停在审批时提问、可新跑只读查询、问答随运行封存)、数字推演沙盘(改输入、排除快照行,不往运行里写任何东西)、定时任务(cron、日期变量、补跑与防重叠、站内与 Webhook 通知、跑完自动和上一次对比);核查 agent 的查询结果在工具边界先遮,取自遮罩格的口径卡指标不进报告和可验证报告;以及两轮真实模型验收中发现问题的修复 2026-10-13 09:46:06 +08:00
ThearchyHelios 23f9453409 check-verify:设置页「核查」一节存完之后取今日花费的那次请求,满并行时晚于「已保存」到达,轮询等它(最多 3 秒)再判;单独跑一直通过,check-all 满并行时偶发 2 → 2 2026-10-12 23:23:01 +08:00
ThearchyHelios fc628a86a2 合入期 5 验收修复 N1:取自遮罩格的口径卡指标不进报告文档和可验证报告——写作目录与文档证据目录写「已遮罩」,引用它的 [[m:…]] 由报告自查拦下;转抄上游口径卡的遮罩在指标依赖图上一次算出最小不动点(循环自引用不误判、不再指数耗时),上游卡在任何一次执行里有遮罩指标时转抄一律不给;可验证报告的显示文字核对改成白名单,紧挨着的数字、小数点、真负号判不通过,易混字、量级单位、删除线、方向字符判无法核对,有一项无法核对总览就不给绿色并提示对照服务端封存哈希 2026-10-12 23:05:18 +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 652576bab3 验收第二轮的两处说法:审批质询整理回答那一步超时时,不再建议「缩小问题范围」(问题再小也要整理),改说调大时长上限或换用更快的核查模型,查询中途触顶的那句另补上可调大上限;反方判「被推翻」却没给理由时一句话说清「但没有给出理由」,不再先说「理由没有引用到任何查询结果」再接「反方没有给出理由」,固定的那句补上句号 2026-10-12 15:55:19 +08:00
ThearchyHelios ec033a945d 修好报告证据回归测试的偶发失败:假模型按共用列表的最后一项(budgets[-1])认这一次抽取要的额度,几个 Agent 并行抽取时,别的 Agent 刚要的大额度会算到这一个头上,该截断重试的这次成了一次过;改成额度跟着发起抽取的那个任务走(ContextVar)。单独连跑 30 次全过(以前约五到十二次挂一次),产品代码没有竞争 2026-10-12 14:26:43 +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 10653ffd3e 认不全写法的名单补上 Postgres 扩展里记着别的会话 SQL 的视图:pg_stat_monitor(语句原文)、pg_qualstats(条件里的常量)、pg_store_plans(执行计划),交回的就是带号码的原文,和 pg_stat_statements 同一类,工具边界整份遮、可验证报告只给哈希(K3b 统一复核留下的一条) 2026-10-12 13:14:36 +08:00
ThearchyHelios 89a4bc8cfc 合入期 5 验收修复 M1:核查 agent 正文里的依据标记不再断句——只装着依据的括号(含【】[]〔〕[])连同里面的停顿标点一起去掉,去掉之后按真正挨上的两个字补空格,两个数不再并成一个;核查 agent 的提示词改成依据写在句末;收尾超时照实记 timeout_s;没给理由时照实说没有给出理由 2026-10-12 13:12:20 +08:00
ThearchyHelios b6a33b4ee2 合入期 5 前置修复 K3b:工具边界遮罩收口——分析出意外、(表达式).* 展开、把 SQL 或表名写成字符串参数的函数、记着别的会话 SQL 的系统视图与 SHOW / EXPLAIN、当一张表用的 VALUES 读到遮罩列时整份遮;按值遮只换文字格、数值证据原样并记下换过的格子;分档标签一档一行时照常显示;交给核查 agent 的证据摘录先遮,反方理由加最后一道关;长 CTE 链的分析有缓存与步数上限 2026-10-12 13:12:10 +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 60be16a0bb M1 复核修正(第 3 轮):依据两边什么都没有时也判粘连,两个数不再并成一个;只装着依据的括号认【】[]〔〕[];右边紧贴着下文的半角逗号后面补空格
渲染(evidence._tidy):
- 上一轮只沿着去掉的字往两边找粘连:依据前后没有空白、括号、标点时没有切口,「华东 [[v:Q1.r0.销售额]][[see:Q1]]
  [[v:Q1.r0.订单数]] 笔」渲染、组装都是「4,919.5212 笔」,「[[v:…]][[see:Q1]]2 月」是「4,919.52 月」,「**华东 [[v:…]]**
  [[see:Q1]]2 月」组装出「华东 4,919.52 月」,verify_doc 都不报。现在每个依据(连着写的一串、只装着依据的括号都算)
  两边都判(_glue 看所有不显示的字,不只看切口),会读成一串的补一个空格:这一片有去掉的字的照旧换掉头一个,没有的
  插在头一个依据前面(粗体收尾的星号外面)
- 只装着依据的括号认【】、[](全角半角混用也算)、〔〕、[],和()一样连括号去掉,外面悬着的停顿标点照原规则收拾;
  依据在这些括号开头、末尾紧挨着分隔标点的,同()一样收拾。核查 agent 拿到的查询结果以「【证据 Qn】」开头,模型照着
  写成「【[[see:Q1]]】」,以前渲染成「【】」
- 右边是写作者紧贴着下文写的半角逗号的(「1,200([[see:Q1]]),900」去掉括号读成「1,200,900」),空格补在逗号后面
  (同「212,[[see:Q1]],5」→「212, 5」)。上一轮把这一类当成可以不管的「),5」写法;和基线 58a6759 逐份比,结构化组合里
  有 2481 份是上一轮去掉括号之后才并成一个数的(「增长 12([[see:Q1]]),212 笔」→「增长 12,212 笔」),现在都隔开了
- 找挨上的字时也越过删除线的两个波浪线:前端照样画出删去的数,挨着后面的数读
- 流式渲染把这几种括号、半角方括号、波浪线也攒到后面的字来了再放;半角「]」攒着时,标记收尾的「]]」和标记里末尾的
  空白不算,标记整个放出去,从它后面攒起

不含依据的文档渲染结果、内容哈希逐字不变:随机 1.6 万份不含依据的文档和基线逐份比过,BEFORE 两份哈希照旧。

测试:依据两边什么都没有(数、标记、粗体、斜体、删除线、连着写的一串)、几种括号(只装着依据、全角半角混用、套着、
和别的括号连着写、开头末尾带标点、不含依据的不动)、半角逗号的用例;结构化组合加上两种括号,中间只有依据的也算;流式
渲染、随机语料加上几种括号和波浪线;审批质询、核查 agent、反方审稿、双盲复算各补一个端到端用例。15 处改动逐一去掉实现,
相关测试都变红(第 2 轮的 7 处也重跑过,照样变红)。另在测试之外:复核用的抽查脚本 6000 份 × 6 个种子只剩写作者自己
写成「212,,2」的一份;结构化组合 29.4 万份、随机含依据的 1.6 万份和基线比没有新并成的数,流式逐字、随机分块都等于整篇
渲染。
2026-10-12 12:24:14 +08:00
ThearchyHelios 45987748ef K3b 复核修正(第 3 轮):VALUES 当一张表用又读到遮罩列的整份遮,列名按方言认;sys 库读 performance_schema 的 ps_* 函数进认不全的名单
- VALUES(复核 major,基线就有):_function_columns 按 Postgres、SQLite 的习惯把 VALUES 的列记成 column1…,MySQL 8.0
  实际叫 column_0、column_1…(真库实测),派生表、CTE、LATERAL 里的 VALUES ROW 取了号码,外层按名字取、照原名带出时
  对不上,号码原样交给模型、落库;MariaDB 拿第一行的值当列名,同样对不上。现在 VALUES 当一张表用(FROM、JOIN、
  LATERAL 里的,WITH 里的一段,UNION 的一支,整条就是它,_values_table)又读到遮罩列(含派生出来的名字)的,不论哪个
  库、列怎么起名,整份遮。套了括号的 VALUES(整条、UNION 的一支)解析器原样挂在树上、不在任何 SELECT 的 FROM 里,以前
  哪个库都没认(Postgres 也漏),一并收口。IN / ANY / EXISTS、标量子查询里的 VALUES 不算:值经外层的表达式带出,或者
  只用来筛行
- 列名按方言认(_values_names,_function_columns 用同一套):Postgres、SQLite 叫 column1…,MySQL 叫 column_0…(一行
  ROW(…) 摊开数列),写了列名表的按列名表(Postgres 的列名表只改前几列),MariaDB、Oracle 认不准记 None。整份遮时只收
  值取自遮罩列的那几列的值(_values_taken 按位置):以前 VALUES 按表值函数认,出的每一列(连同 key、value、别名)都算,
  同一行里没碰遮罩列的区域收成遮罩值,在同一次核查里处处被换掉
- 行为变化:Postgres、SQLite 的 LATERAL VALUES 读到遮罩列,以前只遮那几列,现在整份遮(多遮,同一份里的编号也遮);
  原来「VALUES 里直接写遮罩列只遮那一列」的用例改成整份遮
- sys 库(复核 minor):INDIRECT_NAMES 的 sys 规则补上按 sys.ps_ 开头认的函数(ps_thread_trx_info 交回线程的事务里执行
  过的语句原文,ps_thread_stack 同类;只交回编号、开关的 ps_thread_id、ps_is_* 一并算,多遮;不写 sys. 的要默认库就是
  sys 才执行得了,不认,同 sys 的视图)。工具边界和可验证报告共用这一份名单,报告不再判它没碰遮罩列、照常附带快照
- 质询模块说明的已知局限同步

补测试:VALUES 当一张表用 × MySQL(派生表、LATERAL、CTE、外层改名、JOIN LATERAL、LATERAL 子查询、标量子查询、派生
出来的名字、UNION 第一支、整条套括号、派生表里 UNION 的一支)、MariaDB 两种、Postgres 三种、SQLite 一种;三种没读到
遮罩列的对照;四种写法的收值(号码收、区域不收)和 (表达式).* 之后不按位置收;_function_columns 四种列名、两种认不准;
核查 agent 真实查询工具上的端到端(复核点名的三条 MySQL 写法);sys.ps_* 六种写法、三种不该误伤的对照、可验证报告
两种、端到端一条。逐项去掉实现(整份遮、MySQL 的起名、按位置收值、当一张表用的位置、整条就是 VALUES、VALUES 不按表值
函数认、摊开 ROW、列名表、_function_columns 的起名、(表达式).* 之后停、MariaDB / Oracle 认不准、sys.ps_),对应的测试
都变红。另在 MySQL 8.0.46、Postgres 18 临时实例上经核查 agent 的真实查询工具复跑 28 条(MySQL 的 VALUES 14 条、对照
4 条、sys 函数 4 条,Postgres 的 VALUES 6 条):交给模型的、落库的、通用工件接口给的都没有号码;2b5989e 上其中 16 条漏
号码(sys.ps_thread_stack 在只读事务里执行不了,前后一样)。
2026-10-12 12:18:34 +08:00
ThearchyHelios ce36aabe92 合入期 5 验收修复 M3:可验证报告核对正文显示的文字与引用的值一致——文字取值逐字比对,数字按服务端的显示规则(千分位、小数位、百分数、万 / 亿换算、单位)核对,认不出的格式判无法核对而不是通过;紧挨数字的不可见字符、缩进挤出屏幕的列表一并判不通过 2026-10-12 11:42:06 +08:00
ThearchyHelios d4132daea5 合入期 5 验收修复 M4:单个工作流接口的 run_count 与列表一致;触发历史的翻页游标改成 Z 结尾、放进地址不用编码,老写法照样认;db_schema 认写成一个字符串的 JSON 数组;双盲复算「规范化后不同的行」改成每个条件一行,两边相同的条件不再因换行位置不同被标成差异 2026-10-12 11:42:05 +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