Commit Graph

357 Commits

Author SHA1 Message Date
ThearchyHelios 2935ac5d67 合入 nr8/a 的 3403a0b2(文案检查:地址示例的半角标点登记进 copy-allow.json) 2026-10-19 12:48:13 +08:00
ThearchyHelios 3403a0b2cc 文案检查:应用库、断点库地址写错时报错里给的地址示例(postgresql+asyncpg://用户:密码@主机:5432/库名 等)登记进 copy-allow.json——://、:、@ 是地址语法,用户照着改环境变量,不能换成全角 2026-10-19 12:35:04 +08:00
ThearchyHelios e6a3ee8f95 转发运行事件时跳过不认识的事件种类(回放照样读得到);test-multiprocess.sh 不带参数时 macOS 的 bash 3.2 报 args 未定义,参数直接原样交给 pytest 2026-10-19 12:30:30 +08:00
ThearchyHelios 4a80936c38 多进程的跑法和说法:prod.sh 加 --workers(AGENTLAB_WORKERS,SQLite 时大于 1 先拦下),Docker 入口按 AGENTLAB_WORKERS 起 uvicorn --workers,dev.sh 写明开发时单进程;README 把各处「单进程前提」改成实话——SQLite 单进程(第二个进程拒绝启动),PostgreSQL 可多进程,新增「多进程」一节:怎么起、配置项、认领和租约与各类接手规矩、跨进程停止、运行并发的四类与缺省、调度当班、实时流、进程里的账和缓存(哪些进了库、哪些留在进程里及其影响)、多台机器的条件(共享存储同一路径、对时、NFS 上 SQLite 文件的实话)、升级要停掉全部进程、多进程端到端测试;deploy/README 补多进程。按需视图的锁改成按应用取(每日上限几个键之间也数得准),出具的锁改成全站一把(每日上限是全站的) 2026-10-19 12:08:17 +08:00
ThearchyHelios 1acf960312 多进程端到端验收:scripts/test-multiprocess.sh 用本机 postgres:16 起临时库,tests/test_multiprocess_e2e.py(缺省跳过,AGENTLAB_MULTIPROCESS_E2E=1)在上面起两个 uvicorn 工作进程,用演示模型跑七个场景——两个进程都登记、一个当班;运行由接到请求的进程认领,另一个进程上的流收得到实时事件和流式增量,同一个审批决定同时发给两边只执行一次,两边事件流不重不漏、封存核对得上;跨进程停止;定时只触发一次;全站一个名额时评测的作答运行排着队,后来的问数据运行先拿到名额;两个进程同时记同一本每日账不越过上限;强杀一个进程后在跑的运行被照实标中断、停在审批上的照常在另一个进程上批完、当班交接。顺带修:等名额时被停止也照实收成已取消(以前停在排队中);当班的本地余量不超过租约的四分之一(租约调短时一直不当班);启动清理上传半成品时没有别的活着的进程就全清;文件锁守卫的几项测试只在 SQLite 跑;问数据事件日志清理那一拍不带时刻时按现在算 2026-10-19 12:03:35 +08:00
ThearchyHelios 9a0d87aa6e 合入遗留收口分支 nr8/l(问数据心跳不落库与事件日志清理、续跑重新核对身份、事件触发批量查询与去抖边界、子图编号与驳回出口等),W2-b 在此之上做多进程协调 2026-10-19 10:46:34 +08:00
ThearchyHelios 76290baaf1 问数据的心跳只落换了阶段的那一拍:浏览器检查发现刷新后过程里「规划」那一行没了——页面按心跳的阶段画那一行,全都不落库就回放不出来。现在换了阶段的那一拍(规划 → 查看 → 搭建……)照落,同一阶段接着的保活心跳才只在流上发、不落库;页面接着的心跳顶替上一拍、不叠成好几条。检查脚本的伪服务端照同一个规矩,「一条只收一份」比心跳之外的操作 2026-10-19 10:41:06 +08:00
ThearchyHelios 5e6ba12678 断点库模块去掉没用上的 kind();test-postgres.sh 的注释照现在的连接池写法改 2026-10-19 10:27:17 +08:00
ThearchyHelios 2d108d116f 表结构变了之后口径凑不齐参数时照实记下:以前不试算、也不记日志,一声不响地跳过。现在记一条日志写缺哪几个参数(必填、没给值也没有缺省值的入口字段)和参数本来从哪来,同时写进变化记录的 affects.probes(同一版只记一条),变化页的「影响」一块写「「x」v3:缺少参数 start、end,没有试算」;同一条变化再被探查到时这份记录不丢。变化接口给的 affects 缺的几项补上空的 2026-10-19 10:10:38 +08:00
ThearchyHelios 71d535c4ce 对账要人选对照时按逐格比对的结论预选:这一列单独比和口径取数的某一列等价(ledger/match._cells 证明了),口径卡上只读那一格的指标就是它最可能的对照,409 的 options 里给 suggested;对账框照它预选、标「预选」,人可以改。只是「相关」的那一格不预选(比到的是第一个试的列,不是最像的),一个口径列对上几个指标的也不预选 2026-10-19 10:05:04 +08:00
ThearchyHelios 2e7d6103ea 应用库可移植到 PostgreSQL:AGENTLAB_DATABASE_URL 设成 postgresql+asyncpg://… 时整个应用库用 PostgreSQL,断点用官方的 langgraph-checkpoint-postgres(同一个库,AGENTLAB_CHECKPOINT_URL 可另给);不设时照旧是数据目录里的 SQLite,行为不变
- 配置:database_url、checkpoint_url(启动时校验写法,只认 PostgreSQL)、连接池四项;启动日志写用的是哪种库(主机、库名、用户,不写密码)
- 引擎(db/base.make_engine):SQLite 照旧 WAL、外键、忙等;PostgreSQL 用连接池、探活、会话时区 UTC,装上方言调整(db/postgres.py):建表时 String(n) 是不限长的 VARCHAR(SQLite 从不查长度,导过来的存量也可能超长)、ORDER BY 里可空列的 NULL 位置照 SQLite 补写(升序在前、降序在后,窗口函数里同样);Integer 列在 PostgreSQL 上是 BIGINT(列挂到表上时换成 with_variant,绑定参数跟着列按 BIGINT 转换);JSON 列两边都存原文(PostgreSQL 的 json,不用 JSONB:JSONB 重排对象里的键,快照的列序、表的先后读回来就变了);JSON 里的 NaN 写成 null、NUL 去掉(PostgreSQL 不收)
- 迁移按方言:已有的列和索引用 inspector 认;PostgreSQL 上补列的类型取模型里这一列的、缺省值取迁移表里的(布尔 0/1 换成 false/true),ADD COLUMN IF NOT EXISTS;去重语句里的布尔按方言写;部分唯一索引补 postgresql_where;init_db 在 PostgreSQL 上拿咨询锁(几个进程同时启动不撞)
- 应用库上的 SQLite 专用写法改成按方言编译的表达式(db/portable.py):json_extract 的十几处(口径召回、出具、对账、个人应用、幂等键、访问控制、数据源变化通知、剖析任务、待办超时)换成 json_eq / json_flag / json_text,json_type 换成 json_is_string(两种库同一套带类型的比较);能力登记的 sqlite insert 换成按会话方言的 insert_ignore;能力使用次数的 json_each 按方言分支;附件「没绑记录」的条件不靠 json 的等号;按报错文字认唯一约束的地方换成 unique_violation(按表和列认,两种库的报错都认得)
- 断点(engine/checkpoints.py):PostgreSQL 时开 psycopg 连接池、在咨询锁里 setup;runner 只认 BaseCheckpointSaver,读断点仍只走 saver 的公开接口
- 依赖:新 extra postgres(asyncpg、psycopg[binary] 3、psycopg-pool、langgraph-checkpoint-postgres 3.1.2);langgraph-checkpoint 卡在 <4.3(断点格式就在这个包里,postgres 包新版要 4.3,不动已装的 4.2.0);锁文件补上新包
- 运行收尾:记 action.unknown、安排核实做完才把运行摘掉(以前先摘掉,等「不在跑了」再读事件的一方在库慢时读不到这一条)
- 测试:AGENTLAB_TEST_DATABASE_URL 时跑在 PostgreSQL 上(每个 xdist 进程建自己的库、按事件循环分的连接池 tests/pgpool.py),不设时盖掉环境里的数据库地址照旧用 SQLite;scripts/test-postgres.sh 起临时的 postgres:16 容器跑全量;sqlite_only 标记;另开连接改库的几个竞态测试、触发器测试改成两种库都能跑(tests/appdb.py);新增 test_db_portable 守着方言调整、JSON 键序、超长字符串、大整数、NULL 排序、时区、PostgreSQL 老库迁移
2026-10-19 09:52:09 +08:00
ThearchyHelios 358206312e 事件触发的规模:定时任务列表里每个事件触发任务「有几条在等」一次查齐(outbox.pending_for_many:待派发数一条 SQL 按任务分组算,窗口要看的事件一次读出),不再每行查一次;每一拍派发只读触发条件的事件种类、对象对得上的任务(SQLAlchemy 的通用 JSON 访问),保存时查环一层查一次、只顺着「上游工作流运行成功结束」的边找;选对象(trigger-options)按事件、关键字查、一页最多 100 个、more 说还有没有,当前选中的总在里面,编辑页一页没列完时多一个按名称查找。顺带修:等着的时候任务改了条件、最早那条不再合条件时,「什么时候合成触发」按剩下的最早一条算(列表上的时刻和真发起的一致);一个窗口的结束时刻和这个任务已有的另一次触发撞在同一刻(别的期次早一拍发了)时往后挪,那几条事件照常发起,不再被记到已有的触发上 2026-10-19 09:46:47 +08:00
ThearchyHelios edde451d19 问数据事件日志:助手的心跳不落库、已结束的轮次按期清理。心跳(模型几秒没出声时的 heartbeat 操作)是纯保活,以前每 3 秒落一条库;现在只在本进程里记最近的一拍(chat/log.beat),流上发一条不带 seq 的,重连时流先补最近的那一拍,之后落了任何事件就作废;页面照收不带 seq 的心跳、不动收到的最后一个 seq。其余事件照落(第 2 波跨进程从库里按 seq 追)。已结束(成功、失败、取消、中断)超过 14 天的轮次整轮删事件日志(chat/log.purge,挂在调度循环的那一拍里,一小时最多一次):重开已结束的一轮读的是 conversation_turns 那一行,不读事件日志;任务行留着,seq 接着发号。README 数据位置写明 2026-10-19 09:34:14 +08:00
ThearchyHelios 17e99cd76c 驳回出口之后,待办、通知、Webhook 照实说转到哪:中断内容带上驳回之后去哪(engine/replay.reject_route:接了驳回出口写转到哪几步,没接的写运行就此结束,审批没接、没设驳回即终止的写这一路到此为止),待办卡的提示、驳回按钮、驳回后的提示、处理过的「结果」照它说,不再一律写「转入驳回分支」「本次运行终止」;超时驳回不再露出英文结论码;双盲裁决、动作确认被驳回的提示同样照它说。子工作流里的关卡走驳回出口时,名字记成「子工作流 › x」(RunContext.global_label),走过的那几步交回父图的 trail,父运行的终态事件照实带上途经驳回,实例页、通知写「「子工作流 › 把关」被驳回,转到「子工作流 › 退回」」,不写内部 id、不写成已完成。定时任务的 Webhook:照驳回那条路成功结束的,标题、状态写途经驳回,另起一行写谁被驳回、转到哪一步 2026-10-19 08:59:15 +08:00
ThearchyHelios c0739dfd5d 合入 W1-c 数据事件触发:定时任务加「事件触发」(上传表格出新一期、上游工作流正式运行成功结束、数据源有要处理的变化),事件在发生处写进待派发事件、调度循环去抖派发;保存时与运行时防环;{{ event.* }} 模板变量;途经驳回、应用补算的缺省不认(可勾选);积压一拍处理完、过期的合成一条跳过;按期次分窗口;定时页可选「定时 / 事件触发」 2026-10-18 18:23:33 +08:00
ThearchyHelios 3d5fb19fbd 合入 W1-b 子工作流证据交回父图 + 驳回出口:子图每一步进同一个运行的事件流;子图出口字段带出处,父图口径卡、报告跨子图追到原始数据(运行时、证据面板、静态检查同一套,最多 3 层);报告目录收进子图里的查询和口径卡;审批、动作确认、代码和工具审批、双盲裁决可接「驳回」出口,驳回后沿出口往下走(不接时行为不变),动作确认走出口不发送;发布检查拦下走不到结束的驳回路径;实例页、通知写「被驳回,转到 X」;子图里的报告按全局 id 记、父图只认自己的报告 2026-10-18 18:23:15 +08:00
ThearchyHelios 3e6032bdca 复核修正(前端):节点计数、并行数、「当前在跑」不把子工作流里的步骤另算;子图那一步写「子工作流 › 那一步」
- B5 run/trace:子工作流里的步骤(isSubStep:节点 id「子工作流节点 id/…」)算在子工作流那一步里——完成数不另算(以前运行详情
  会写「7/3」),没有 run.started 时的分母也不算它们;Telemetry 的「当前「X」等 N 个」同一个规矩,子工作流和它里面那一步不算成
  两个同时在跑
- B6 run/trace.stepLabel:图上没有的子图步骤接上子工作流的名字(「取数子流程 › 查订单」,和服务端终态事件的 label 同一个拼法,
  名字取 node.started 记的);运行胶囊(RunHud)、泳道(RunTimeline)的失败、阻断说法和泳道名、记录页的失败横幅与航迹
  (RunDetailView.labelOf)都用它,不再写「失败于「sub/x」」

检查脚本:check-decode 加两段(子工作流步骤的完成数、并行数、当前在跑;出错在子图里那一步时的名字)
2026-10-18 18:18:53 +08:00
ThearchyHelios 656a550408 数据事件触发按复核意见修正:途经驳回、去抖积压、source.changed 补写、按期次分窗口、补算缺省不认、示例出口字段同一套过滤
M1 途经驳回(编排者已定):outbox.stage_run_finished 收可选的 rejected_via(缺省 None 即没途经驳回),事件内容带 rejected 和
rejected_via,说法接「(途经驳回)」,模板有 {{ event.rejected }}(true / false)。触发条件缺省只认没途经驳回的,trigger 加
include_rejected(界面「也认途经驳回的」勾选,说明照实写)。runner._finalize 把 _rejected_via(state) 传进来那一下留给编排者
在合并时接(runner 的 _rejected_via 在 W1-b 的分支上);测试直接调 stage_run_finished 传参覆盖。

C1 去抖积压:以前一拍只走一个窗口,积压时后面的越等越久、全过了宽限,而且每个窗口各记一条跳过,原因还说调度没在跑。
现在 _drain 按发生时刻把等着的事件切成窗口,一拍里把到点的处理完(最多 100 个窗口、5000 条);排在前面已过补发宽限的合成
一条 skipped_misfire(合并了几次事件、几个窗口、时间跨度,上传表格另写合掉的期次),派给任务时已经晚于宽限才说「调度未运行」,
否则照实说积压;宽限内的照常发起(照重叠规则跳过的照实记)。

C3 source.changed:这一处确实没法和变化记录同一个事务(一次探查、剖析的变化分好几批落库,一批只触发一次要等任务结束才知道),
改成说实话:models_triggers 的说明写清哪两种同事务、哪一种不是。trigger_events 加 dedupe_key(source.changed:<任务号>,唯一),
emit_source_changed 按它去重;调度的一拍(刚起的服务第一拍就补,之后每 10 分钟)由 backfill_source_changes 按任务号补写:2 天内
测到、还开着的要处理级变化,任务已结束却没有事件的补一条。分组在 Python 里做,不用各库写法不同的 JSON 取值。

C4 按期次分窗口:triggers.window_key 让上传表格按期次各自成窗口,9 月、10 月连着启用各有各的触发;同一期的重传照旧合并。
两个窗口结束在同一刻时后一个挪 1 微秒,fire_at 不撞唯一约束。

C5 应用补算:workflow.finished 缺省不认 app_backfill 发起的(升版补算连发好几条、各是某一期的历史输入),trigger 加
include_backfill(界面「也认应用补算的」),选了「只认应用补算」时本来就认;说法写「途经驳回、应用补算的不算」。

C6 示例出口字段:triggers.outputs_of 一处过滤「_」开头的键,真派发、预览、立即运行共用;示例事件也按 matches 跳过缺省不认的
途经驳回、应用补算,取合条件的最近一次。

测试:新加 test_schedule_events_review.py(11 项,先写、先看着失败;去掉 matches 的驳回判断、把每拍窗口数改回 1 回跑,对应用例
各自失败),test_schedule_events_api.py 加一项「也认」两项经接口存取和说法;check-schedules 加「上游工作流的请求体」一段、纯函数
几条、触发历史里合并跳过那一行的夹具。
验证:后端全量 14479 通过;tsc、check-copy;check-schedules 447 项、check-runs 327 项通过(拿锁、--stacks 1)。
2026-10-18 18:09:20 +08:00
ThearchyHelios d6318b639d 问数据页的复核修正(前端):使用者不给「继续运行」,两个标签页同时打开停在半路的一轮时后到的那个接着看
- 使用者(user 角色)续不了运行(服务端照 POST /api/runs/{id}/continue 的老规矩回 403):补救区不摆「继续运行」,服务重启打断的
  那一轮说明里也不叫它去点,改说「如需整轮重来,请点击「重新运行本轮」」(lib/terms 的 CHAT_TURN_TEXT);重试本轮、重新运行本轮照常。
  以前这个按钮对使用者也摆着,点了只弹一句 403。
- 两个标签页同时打开停在半路的一轮:都会请服务端接着收尾,服务端现在只起得来一次,后到的那个收到 409 chat_turn_busy 时不再说
  「无法确认本轮的当前状态」,改成问一下这一轮现在怎样——在跑就从这一次尝试的第一条接着播,收了尾就照那一行摆。
- scripts/check-chat.mjs 新加两段:「使用者(user 角色)」(伪造 /api/auth/me 认出使用者:中断的、跑挂的都不给继续运行,一次续跑都
  不发)、「两个标签页同时打开」(服务端只接着收尾一次,两边都收尾、答案一样、都不写库)。去掉修复回跑,这两段都会失败。
2026-10-18 18:07:03 +08:00
ThearchyHelios fa9725adf2 问数据一轮的收尾补漏:接着收尾不算占着对话,实时流没等到结局不再转圈,刷新后接着播的过程照实时的样子摆
- 一段对话里停在半路的几轮(老轮次、服务重启后停着的)要一起交给服务端收尾:resume 不建图、不发起运行,不再按「这段对话正忙」
  拒掉第二轮(以前打开这样的对话,只有第一轮收得了尾)。测试先写、去掉修复回跑会失败。
- 实时流结束了却没见到这一轮的 end(服务端那一轮出了岔子、这一轮被删了或没权限了):回服务端问一次那一行,照它摆;问不到就
  照实说「无法确认本轮的当前状态」,给「重新核对」。重新核对一轮还没有运行的:问服务端它在不在跑,在跑接着播。
- 刷新、关掉再打开后接着播的那一轮就是正在跑的一轮:建图的过程照实时的样子一直摆着,不当成要点开才取的历史轮次
  (check-chat「刷新后接着看」一段多守这一条,去掉修复回跑会失败)。
2026-10-18 16:55:30 +08:00
ThearchyHelios 5ff3e1136d 问数据整轮放到服务端跑(前端):store/chat.ts 改成「发起 + 播放」,断线按 seq 重连补齐,刷新、关掉再打开接着看
为什么:一轮问数据搬到服务端之后(上一个提交),页面不该再推这一轮:建图那条流、发起运行、复核、按复核重来、落库都和页面
绑在一起,页面一断这一轮就停。现在页面只发起、只看,要不要运行、要不要重来、什么时候交付都照服务端说的。

做了什么:
- 新的 api/chatTurns.ts:发起、查询、停止(挂在 api.chatTurns),streamChatTurn 订阅这一轮的事件日志——先回放、再接实时;
  断了按收到的最后一个 seq 自动重连(收到东西马上接着连,连不上按退避),45 秒什么都没收到(服务端 15 秒一拍心跳)当连接死了。
- store/chat.ts:plan / launch / settle / retry 换成发起(launchTurn)+ 播放(play)。收到的操作照原来的渲染逻辑画(画布边收
  边长、过程步骤、思考、查看、用量);收到 run 就接上运行自己的实时流画过程(watch 只画过程,不再判结局);stage 说到了
  哪一步(停在审批上立刻去拿待审批);turn.retry 照原来自动重来那样重置;end 照服务端落库的那一行摆结局(和刷新之后从库里
  恢复的是同一份 restoreTurn)。「重试本轮」「重新运行本轮」「放宽步数」「跑一下」「继续运行」「停止」都走新接口。
- 页面不再写这一轮的结局(不再 PATCH 轮次、不再调 /copilot/review、不再发 POST /api/runs);失败的说法照服务端记的原因
  (meta.cause)按 lib/explain 讲,老轮次记的 failure 照旧认。
- 刷新、关掉再打开:服务端还在跑的一轮(ConversationTurn.job)从这一次尝试的第一条事件接着播;库里停在半路、服务端又没在跑
  的(老轮次、服务重启后停着的)请服务端接着收尾(mode=resume),不在页面上自己收尾。问数据页的显示不变。
- 页面上那份退路(MAX_ATTEMPTS、fillInput、retryInstruction、等复核的计时)去掉:决定只在服务端一处。后端对照测试改成守
  「页面上不再有这几样」。
- scripts/check-chat.mjs:伪造的服务端照 backend/app/chat/job.py 的做法用原来那几份剧本把一轮跑完(生成、发起运行、等运行的剧本
  放完、复核、拼那一行),原有各段照过;守落库的几处改成守「页面不 PATCH 这一轮」和照服务端那一行摆;新加「断线重连补齐」
  「刷新、关掉再打开接着看」「停止(建图中也停得下)」几段,并核对发起、重试、放宽步数、继续运行、停止的请求体。
- 服务端顺带:turn.attempt 带上到目前为止的用量、从什么时候算起(补交付的到运行结束为止),turn.retry 带上换下来的那次运行
  并进之后的用量(页面上的运行壳子里没有用量);接着收尾(resume)不要求运行还在,运行记录删了的照实收成「运行记录不见了」。
2026-10-18 16:49:26 +08:00
ThearchyHelios 38addf8f5d 驳回出口与子工作流证据(前端):画布多一个「驳回」出口、走了驳回出口的那一步画「被驳回」、子工作流里的步骤和证据有名字
接后端两个提交(docs/design/orchestration-round/00-总方案.md §2、§3):

- canvas/nodeDefs:会被人驳回的节点多一个「驳回」出口(id rejected,和后端 REJECT_HANDLE 同一个,中性色):人工节点三种
  模式、双盲复算一律给;沙箱代码只在审批策略是每次审批时给;调用工具选了工具、审批策略不是从不审批时给(数据源的查询
  只读,只在明说每次审批时给)。出口跟着配置算:改成不会被驳回时,studio 原有的出口同步把连在驳回出口上的线收掉;补充输入
  改成审批时普通出口的线跟到「批准」
- run/trace:node.finished 带 outcome=rejected 时这一步收成 rejected(exited,记下转到哪几步),下一次执行开始时清掉;
  子工作流里的步骤不另算一路并行
- run/derive:接了驳回出口的关卡按出口路由(驳回出口 / 其余是普通出口,同 compiler._make_router);走了驳回出口的算
  「送出了数据」,下游照常排队、跑完,普通出口那一侧未到达;退回修改时两条出口都算走过;withSubSteps 把子工作流里的
  步骤排在子工作流那一步后面(泳道、航迹的节点列表)
- run/decode:走了驳回出口的那一步状态 rejected、副标题写谁驳回、备注、转到哪一步;终态写「完成(途经驳回)」和途经的
  那几步(run.finished 的 rejected_via),没有途经的一字不变;子工作流里的步骤名接上子工作流的名字
- run/useNodeView:回放时「走了驳回出口」只说被驳回的那一刻
- canvas/NodeCard、pages/runs/TracePane:走了驳回出口的节点卡写「被驳回,转到「X」」,航迹节点卡写出口和转到哪,关键时刻
  多一条「「审批」被驳回,转到「X」」、结局写「运行完成(途经驳回)」
- run/EvidencePanel、types:输入来源写明经哪个子工作流的哪个出口字段;子工作流里的节点(「sub/…」,画布上没有)照证据接口
  给的名字写(node_label、subgraph_label),悬停写 id;停在子工作流入口的写「子工作流的运行输入」
- lib/terms:REJECTED_TEXT 加出口、走出口那一步、途经驳回的说法;EVIDENCE_TEXT 加经子工作流的说法

检查脚本:check-decode(驳回出口的步骤、航迹、走过的边、跑到一半、批准走普通出口;子工作流步骤名)、check-run-states
(reject-exit:卡片状态与剪影、槽里写转到哪、驳回边走过批准边没走、运行成功)、check-studio(各类节点的出口、能连能画、
改配置收掉驳回线、改模式线跟过去)、check-evidence(subgraph:输入来源写明经哪个子工作流、子图节点写名字)
2026-10-18 16:30:39 +08:00
ThearchyHelios 3f1eeff841 数据事件触发(界面):定时页新建时选「定时 / 事件触发」、事件那一节、列表与详情的等待状态、触发历史和运行详情的「由事件触发」
做了什么:
- 新建定时任务(目标是工作流时)先选怎么触发:定时 / 事件触发(TriggerEditor 的 TriggerModePicker);修改时只读地写出触发方式、
  说明建好之后不能改。选了事件触发,频率那一节换成事件(EventSection):三种事件、对象下拉(能选哪些、不能选的原因由新接口
  GET /api/schedules/trigger-options 给,界面照着画、选不了的置灰并写原因)、上传表格的期次(只认新增的一期)、上游工作流的
  只认应用 / 只认来源和触发链上限的说明、去抖、时区;换事件种类时对象和过滤清掉。
- 预览按一次事件渲染输入(对象最近一次的事件,没有时照实说是示例值),不列触发时间;变量按事件种类取(api.schedules.eventVariables),
  插得进 {{ event.* }};请求体带 trigger_kind、trigger,cron 交空串;修改时只交改了的触发条件。model.ts 加 TriggerForm 与
  triggerBody / switchEvent,表单问题里事件触发不查频率、要求选对象;服务端 422 指 trigger 时落到事件那一节。
- 列表、详情:「事件触发」标签,频率处写触发说明;下次运行写在等什么(去抖中收到几次、何时合成一次触发;有事件等待派发;调度
  没开时照实说不会派发)。触发历史:类型「事件」,写「由事件触发:…」、合并了几次、第几层;立即运行按最近一次事件发起的写
  「按事件:…」并标示例值。运行详情页头写「由事件触发:…(定时任务「X」)」(RunDetailView 只多传一个 trigger 属性),立即运行
  按事件发起的写「立即运行定时任务「X」,按事件:…」,不说成由事件触发;应用页印章同样不算。
- 文案进 lib/termsTrigger.ts;SCHEDULE_TEXT 只补触发类型「事件」和「还需处理」里的「触发事件」。立即运行按示例事件的说法
  不再在服务端加「(示例值)」后缀,是不是示例值看 real。

为什么:总方案 §4 要求定时页能建事件触发的任务、列表 / 详情 / 触发历史 / 记录页照实显示;能不能选、为什么由服务端判,界面不放逻辑。

验证:tsc、check-copy;check-schedules 加纯函数一段(表单 ⇄ 请求体)和三段页面(新建的请求体、列表 / 详情 / 触发历史、运行详情
页头,含 390px 浅色),假接口加了触发选项、事件预览、事件变量、事件触发任务的夹具,写请求断言请求体;原有各段照过;check-runs 照过。
2026-10-18 16:11:55 +08:00
ThearchyHelios 271bc6e782 口径标签逐格判:引用了好几列的查询,每个数按它自己那一格标
真实模型下问「上周的销售额是多少」,助手写 SUM(amount) AS 销售额, COUNT(*) AS 订单数, MIN / MAX(paid_date) AS 区间首日 /
末日,报告四列都引用了,口径「周销售」只取 SUM(amount)。按「全部引用列」投影后还是 4 列,对不上口径的 1 列,整条比、
四个数都标相关口径,说明整段兜底。

- ledger/match._cells / _cell(algo 4):整条(含按全部引用列投影)没证明、又引用了这条查询两列以上的,被引用的每一列单独
  投影到那一列,和每份口径的每个指标读的那一列(card_reads;口径版本没有口径卡的按取数的每一列)逐个比,仍只走
  match_template / explain_sql_diff,上次的投影规则照用:投影不了(分组列、DISTINCT……)、过了时限、不可比的格照用整条
  查询的那一个候选。结果记在 queries[].cells {列名: {status, candidates}},另记 one_row(sql_semantics.one_row:不分组的
  聚合,一定只出一行)。整条这一层的结论、候选一字不改;老工件没有 cells,照旧按整条读。
- ledger/labels:单元格按它那一格的结论标(_view);指标用了同一条查询的好几格时,只有那条查询一定只出一行才把逐格的
  结论合起来用(多行的结果里每一列各自对得上,不等于每一行的几列一起对得上)。整题照拍板 L1 不变:每个数都证明来自
  同一份口径才等价;一格证明了、别的格只是相关的整题不等价,原因写「有的数和相关口径不一致,不来自口径」(以前一律说
  「这次的推理」)。出具入口照 ledger/issue 现有判法只在整题等价时给,没有放宽。
- 逐格证明了的口径各处都算上(labels.candidates_of):工件 meta 的 calibers(召回按旧版本反查)、ledger/uses 的使用记录、
  召回时找原答案对应的那一格、E4;E1 另数各种结论各几格(cells),E2 的兜底比例按标签上给人看的那一份说明数。
- GET /runs/{id}/ledger 的 queries 带上逐格的 cells(遮罩同候选);证据片段的 ledger 键、轮次摘要的计数本来就按每个数的
  标签,数据变了、形状不变。前端只补类型;check-ledger 加一段:同一条查询一格来自口径(正文挂小标记)、一格相关(差在哪
  先说多查了几列),整题不等价不给出具。
- 评测逐题比 SQL(eval/score.sql_match)取和期望配上的那一格(score.matched_cells:评分时配上的格),没给时取逐格证明了
  的那一格;结果带 column。runner、rescore 传它。

测试:tests/test_ledger_cells.py(同一条查询一列等价、一列不等价各自标对;两份口径只证明了一份标那一份;口径多个指标按列
配对;指标跨两格只在一行的查询上用逐格结论;分组列、DISTINCT 逐格也不投影;照真实例子造的虚构库真跑一遍:销售额标等价
已证明,订单数、首末日标相关,整题不等价、不给出具、不自动出具,证据片段的 ledger 键一致;评测取配上的那一格)。去掉逐格
再跑,10 条失败;去掉「一行才合起来用」、去掉评测取格,各 1 条失败。
2026-10-17 13:07:19 +08:00
ThearchyHelios f8d89e780c 合入 nr6/b:评测「期望没有数据」只认数值格和叙述里的数、逐题 E1 比产出答案的那条查询、判错时给配对上的那一格、估不出金额时不写 0、没做完的模型调用也计一次、助手只给思考不给操作时自动重来一次(问数据与评测同一个决定)、目录两种计数照实说、自由形应用入口与岗位显示名;评分规则升到第 2 版 2026-10-17 12:28:04 +08:00
ThearchyHelios 67b13a921b 评测页检查守住估不出金额时的写法;估算说明去掉重复的半句
接着「评测估算和每题平均花费:有估不出金额的调用时不再写成 0 美元」那一项:check-evals 加一节,在浏览器里核对开跑对话框
上一次都估不出时写「估不出花费」和原因、不出现 $0,估出一部分时写「至少约 …(每项至少约 …)」;评测总览都估不出时花费写
「金额无法估算」、不写每题平均,估出一部分时写「≥」和「每题至少约」。

在浏览器里看到「估不出花费 · …估不出花费:…」说了两遍,runner.estimate 全估不出那一句的说明去掉了重复的「估不出花费」。

验证:check-evals 110 项全过(新加 5 项);test_eval_runner.py::test_the_estimate_says_it_cannot_price_instead_of_zero 通过。
2026-10-17 12:11:55 +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 3dc5f5add4 助手只写了思考、一个操作都没给时自动重来一次:问数据和评测走同一个决定
真实模型验收里 deepseek 偶发只出思考、不出操作,生成过程交出 error「助手本轮未完成:模型没有给出任何修改,也没有说明
原因」,问数据这一轮照实报了,但不会自动重来——而这种偶发情况重来一次多半就好,「重来一次」的规矩本来就有
(chat/turn 的 MAX_ATTEMPTS = 2,含第一次)。

- chat/turn:error 也由 next_step 判:机读码是 EMPTY_GENERATION(copilot_empty)的判 retry,别的仍判失败(被截断的不重来:
  额度不变,重来还是截断);error_reason 取重来时交给助手的原因(error 带的 reason,没有就去掉「助手本轮未完成:」前缀);
- api/copilot.answer_ops:一个操作都没给时 CopilotIncomplete 带上这个码;error 操作多带 reason 和 next(retry | fail),和
  final 的 next 一样由服务端定;
- 问数据页(store/chat.ts)照 error.next 走:retry 就带着原因重来一次(同 retry_instruction 的从零重建措辞,次数照
  MAX_ATTEMPTS),试满了才照实报;进度写「助手上一次没有给出任何操作,正在重新生成工作流…」(lib/terms 的 CHAT_RETRY_TEXT);
  第一次建图的用量照样记进这一轮;
- 评测(eval/answer.Driver.drive)用同一个 next_step / error_reason / retry_instruction:先重来一次,还不行才记建图失败、
  助手调用失败;每次自动重来的原因照实记在 turn.retries(没过检查、复核判不可用的重来也记),评测页逐题明细写出来。

测试:test_chat_turn_policy.py 的 test_next_step_branches(error 的两支和 error_reason)、
test_the_frontend_retries_an_error_the_server_says_to_retry、test_answer_ops_says_to_retry_an_empty_generation、
test_the_eval_driver_retries_an_empty_generation_once(重来后回答 / 重来还不行,两次的用量都算);
test_copilot_answer_ops.py 的 SSE 对照多认 error 上新加的 next、reason、code。去掉修复回跑都失败。
浏览器:check-chat 新加 emptyretry 一节(重来一次后照常回答、交回去的话带原因、两次用量都记;两次都不行照实报、不试第三次),
check-chat 840 项全过。
2026-10-17 11:51:34 +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 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 ccf1fb21d2 check-all:第 4 波三项检查的耗时估计按实测改(只影响排队顺序) 2026-10-16 22:42:45 +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 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 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 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 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