Commit Graph

790 Commits

Author SHA1 Message Date
ThearchyHelios d6ecaaa7a3 复核 R-b8(隔离时 asyncio 记一条回调异常):断点写入的守卫改成协程包装、在协程里查 fence——LangGraph 在节点的完成回调里调 aput_writes 拿协程交给后台任务,以前同步包装在回调里就抛 Fenced,每次隔离都打一条「Exception in callback … FuturesDict.on_done」加 traceback;现在异常留在写断点的那个任务里,由 LangGraph 照常收走。补测试:卡住被接手那一条里 asyncio 不记回调异常、不记没人取的任务异常(改前的写法这条不过) 2026-10-19 14:29:12 +08:00
ThearchyHelios 7fcce90f95 复核 R-b7(休眠、时钟偏差下隔离失灵):租约改用库的时钟——续租、登记写 lease_until = 库的 clock_timestamp() + 租约,判活、清理过期登记、版本守卫看谁活着都比库的时钟,调度当班的租约同样按库的时钟接班、续租,本地判还当不当班改看计入休眠的单调钟,机器之间墙钟差多少都不起作用;隔离改用计入休眠的钟(Linux CLOCK_BOOTTIME,macOS clock_gettime(CLOCK_MONOTONIC),取不到退回 monotonic),并且一律同时比墙钟,两只钟里走得多的那只说过了一个租约就算续晚了;续租时两只钟差出一个租约(墙钟跳了、休眠没计)也隔离;续租那一句带上「库里自己的租约还没过期」的条件,过期了或者登记不见了就不再续这个身份、隔离换身份(以前登记不见了是用旧身份重新登记)。补测试:单调钟不走而墙钟过了两个租约、墙钟往回拨,都算续晚了;本机墙钟快一小时,别的进程照样活着、当班租约抢不走;库的时钟过了自己的租约时续租不续、隔离一次 2026-10-19 14:27:55 +08:00
ThearchyHelios 11d3b24592 测试:conftest 把 AGENTLAB_SECRET_KEY、AGENTLAB_SCHEDULER 挪到任何 app.* 导入之前(PostgreSQL 分支先导入 app.db.base 装连接池,settings 那一刻就定下来了,以前单独跑 test_schedule_events_api.py 在 PostgreSQL 上 scheduler_on 是 True);test_trigger_options 按名字(q)查要核对的那几个对象,不再指望一页 100 个装得下同一个库里别的测试建的工作流和数据源 2026-10-19 14:06:20 +08:00
ThearchyHelios 322ba5969b 合入 nr8/b 之后的配合:启动时先等库再做版本检查(cluster/version.preflight 是第一次连库,放在等库之前的话库的容器晚一步起来服务就直接崩),单测核对先后;deploy/README 多进程一段写明内置 PostgreSQL 是直连、不用 AGENTLAB_DATABASE_DIRECT_URL,upgrade 先停掉旧容器(全部工作进程)、备份、再起新版本,正合不许新旧版本同时运行的拦截 2026-10-19 14:06:20 +08:00
ThearchyHelios 5318c33f57 合入 nr8/b 的 ac8b194c(复核 R-b1–R-b6、交互留底的运行名额、先占额度再出具、直连地址 AGENTLAB_DATABASE_DIRECT_URL 和 AGENTLAB_DB_PGBOUNCER、不许新旧版本混跑、prod.sh 和 Docker 入口问 python -m app.cluster workers、镜像带构建号);没有冲突,README、config.py、db/base.py 自动合并 2026-10-19 14:01:07 +08:00
ThearchyHelios c842b536f6 内置 PostgreSQL 的四条取舍:agentlab.env 模板末尾追加注释掉的「内置 PostgreSQL(可选)」一段(POSTGRES_IMAGE、POSTGRES_CONTAINER、DOCKER_NETWORK、POSTGRES_VOLUME、BACKUP_KEEP,缺省值写在注释里,已有的行一行没动);升级前的备份收紧权限——backups/ 起每一层目录 0700、备份文件 0600,属主同数据目录(SQLite 的在 umask 077 下先以 0600 建空文件再交给备份接口写,pg_dump 在 umask 077 下写、目录由 app.ops backup-dir 建和收紧),恢复步骤里写清哪一步要 sudo、内置库的恢复改成在以 10001 运行的临时容器里读备份(不用 sudo);restart 缺省只重启服务(库停着时先把库起来),restart --postgres 连库一起重启,没用内置库时加 --postgres 照实报错;离线包缺省带 PostgreSQL 镜像不变,deploy/README 写清多出约 160 MB、导入后约 0.7 GB;deploy/README 加「首次在 Linux 上切换前的检查」(docker 版本、属主、权限、磁盘空间、整目录备份)。单测核对权限位、restart 两种用法、模板里的注释和 deploy.sh 的缺省值一致 2026-10-19 13:58:00 +08:00
ThearchyHelios ac8b194ca8 评测时限不算排队(续):within 看得更勤(不超过时限的 1/20),一段的头尾有一头在暂停就整段不算——以前一段只看尾巴,拿到名额后的头一段整段算进去,PostgreSQL 全量满载时那条测试偶发超时;测试改成排 2 秒、时限 1 秒,给拿到名额之后的几次写库留够余地 2026-10-19 13:46:09 +08:00
ThearchyHelios 9e6a6db406 deploy.sh 带内置 PostgreSQL:install --postgres 在旁边再起一个 PostgreSQL 容器(镜像小版本固定 postgres:16.15、可用 POSTGRES_IMAGE 改;同一个 docker 网络、端口不对外;数据在 docker 数据卷;密码第一次自动生成在数据目录的 .postgres/、0600,按 POSTGRES_PASSWORD_FILE 和 PGPASSFILE 传,不进镜像、日志和 docker inspect;agentlab.env 什么都不用填)。用过一次的数据目录记在 .postgres/state,之后 install / upgrade / start 不用再加。start、restart 先起库等 pg_isready 再起服务,stop 先停服务再停库,status 显示两个容器,logs --postgres 看库的,uninstall 连库的容器和网络一起删、数据卷和数据目录留着。和外接 PostgreSQL(agentlab.env 里的 AGENTLAB_DATABASE_URL)互斥,照实报错;已有 SQLite 库的数据目录不许 install --postgres(指向 migrate-to-postgres),别的数据目录留下的数据卷不拿来用。upgrade 先停旧服务、自动备份(SQLite 用备份接口拷到 backups/sqlite/,内置库 pg_dump 到 backups/postgres/,各留最近 BACKUP_KEEP 份),备份没做成就把旧服务起回来不升级;POSTGRES_IMAGE 换了时库的容器按新镜像重建、起不来就换回原来的。新增 migrate-to-postgres:停服务 → 备份 → 起库 → copy-to-postgres 先 --dry-run 再正式导入、核对 → 记下已切换 → 按内置库起服务;记下之前哪一步出错都退回 SQLite(服务原样恢复、库的容器停掉、状态记成 migrating),重跑先清空上次导了一半的再导,已切过的什么都不做,不是这个数据目录留下的数据卷不清空。容器、网络、数据卷、端口等可用 DEPLOY_<名字> 环境变量盖过(测试、并排部署)。package-docker.sh 把同一个标签的 PostgreSQL 镜像导出成 postgres-image.tar 一起打包(--no-postgres 不带),标签只在 deploy.sh 里定一处。单测用假的 docker(tests/fake_docker.py)核对先后顺序、生成的参数、互斥和各条回退 2026-10-19 13:43:52 +08:00
ThearchyHelios 93cd32bc97 启动时等库:PostgreSQL 还连不上(和库的容器一起起、库还在初始化)时按退避重试(1、2、4、5、5… 秒),每次照实打一条「应用库还没就绪」,最多等 AGENTLAB_DB_STARTUP_TIMEOUT(缺省 90)秒再把最后一次的错抛出去;密码不对、库不存在这种等也没用的(SQLSTATE 28、3D、42 类)立刻抛;SQLite 不等。新增 python -m app.ops(部署脚本在容器里以镜像用户调的几件小事,只用标准库):内置 PostgreSQL 的密码文件和 pgpass(0600,已有就沿用,密码不打印)、数据目录用哪种库的状态(sqlite / builtin / migrating)、SQLite 库的一致备份(备份接口,含 -wal 里的)和只留最近 N 份。copy-to-postgres 连不上目标库、库报错时一句话说清楚、退出码 1,不再甩一屏调用栈 2026-10-19 13:43:32 +08:00
ThearchyHelios 94fd36027b 测试:隔离那两条先等 slow 前面那一步的断点落库再装「卡住、被接手」——LangGraph 存断点和下一步并行,PostgreSQL 全量满载时 slow 已经开始、断点还在写,一隔离那次写入就被拦下,接手的一边找不到断点(偶发「没有可继续的断点」) 2026-10-19 13:42:10 +08:00
ThearchyHelios bf9e4d4811 测试:额度并发那条同时占的个数降到 10(不超过连接池直接能给的连接数)——全量 -n auto 时 SQLite 的池子各测试共用,排队等连接会把池子的队列绑到前一个测试的事件循环上,这条偶发报 bound to a different event loop 2026-10-19 13:35:17 +08:00
ThearchyHelios 5b24480268 版本守卫拒绝启动的那句话改掉「混跑」(check-copy:「跑」不作动词):不支持新旧版本同时运行,先停掉这些进程再启动新版本 2026-10-19 13:33:07 +08:00
ThearchyHelios 62089f2849 复核「另外两处」:评测每题的时限、算期望的时限都不算排队等运行名额的那一段(within 代替 asyncio.wait_for,作答那次运行在 slots 里还排着队时不走表;算期望的运行排着队时把截止时刻往后挪),满载时不再被记成超时、触发止损;同源队(SourceLanes)跟发名额一样,拿这个源的咨询锁之前备好「哪些别的属主确实不在了」,持锁期间只用持锁的那条连接,拿锁之后才出现的属主这一次当活着。slots 加 waiting(run_id, here=):本进程里的直接看、不查库。补测试:排队 0.8 秒、时限 0.3 秒照样答完不记超时(改前的写法这条不过);within 暂停的那几段不算、不暂停照样超时;同源队持锁期间不查「谁还活着」、没了的进程照样让位、拿锁之后才出现的属主不删 2026-10-19 13:31:46 +08:00
ThearchyHelios f3ff5b9c18 复核 R-b5、R-b6:转发运行事件、读缓存失效通知都从游标往回留一小段重读(运行 64 条、缓存 200 条),按发布过的 seq / 处理过的 id 去重——号先取后提交、号大的先提交时,号小的那一条后到也照样转、照样失效,不越过回放已经发过的那一段;合成之后超长的正文增量按字切成几条(二分找每段最长的前缀,不切坏 UTF-8),不再截掉。补测试:号小的后提交照样转出来、不重复;缓存失效 id 大的先到、小的后到都处理;超长增量切开拼回来一字不少 2026-10-19 13:24:44 +08:00
ThearchyHelios 5578cf137d 复核 R-b4(prod.sh、Docker 入口读不到 .env 里的配置):新增 python -m app.cluster workers——照后端自己的配置(环境变量和 .env 一起读)说起几个工作进程,SQLite 而大于 1 时照实报错、退出码 2;prod.sh 只在命令行给了 --workers 时写进环境变量,进程数一律问后端,Docker 的入口同样问它。补测试:SQLite 而大于 1 拒绝、PostgreSQL 照给的数 2026-10-19 13:23:02 +08:00
ThearchyHelios 5f7100906f 复核 R-b3(SQLite 单进程多出来的写库):SQLite 时守卫已经确认只有本进程——登记只写一次、不续租约、本进程直接当班(不写库)、接手只在启动时做,心跳只做本进程自己攒着的活;运行的名额在 SQLite 下放在进程里(规矩同一套:优先级、类别上限、交互留底,只是不落库),一段运行不再为要名额多写三次库。顺带(复核「另外两处」之二):PostgreSQL 发名额持着全站的锁时不再另取连接查「谁还活着」,拿锁之前备好,不认识的属主这一次当活着。补测试:SQLite 空闲十来拍心跳、要一次名额放一次,PRAGMA data_version 不变(名额落库的写法这条不过);库里的名额行那两条只在 PostgreSQL 上跑 2026-10-19 13:22:05 +08:00
ThearchyHelios 96bb372ef3 复核 R-b2(单进程下周期整理退回判定中的待办):当班进程隔一会儿的那一次接手(trust_mine)不论有没有别的进程,停在 resolving 的待办只收拾停了两个租约时长以上的,启动时又没有别的进程的那一次照旧全收拾;顺带把其余周期调用的整理过一遍——结果未知的写入只补停了两个租约时长以上的(收尾和安排核实之间的不碰),问数据没有任务行的老轮次只在启动时整理(老页面开的轮次建图时也是这个样子)。补测试:判定到一半当班进程来一次,待办照样记已处理、那一票不撤回(改前的写法这条不过) 2026-10-19 13:18:23 +08:00
ThearchyHelios 35ab097b45 复核 R-b1(卡住但没死的进程被当成没了):续租约挪到单独的任务、专用连接(不走连接池,不被同一拍别的活拖住);进程间请求另起任务办,不在心跳里等收尾;新增 cluster/fence 自我隔离——离上次续上租约超过一个租约时长,或者这段执行属于上一次隔离之前,执行在写事件、写断点、开审批、发外部写入、后台任务写库之前就停手(Fenced 是 BaseException,节点里的 except Exception 拦不住),续租时发现续晚了就隔离:停掉手上的运行和后台任务、不写终态,换一个身份重新登记;运行收尾先占住那一行、属主不是自己就不写;别的进程按租约过期再多等一个租约时长才算不在了(两边中间留一段);run_events 的 (run_id, seq) 改成唯一索引(存量库先数重复,有就照实记日志、这一次不建,不让启动失败)。补测试:卡住期间被接手之后不盖终态、不写事件、序号不重;被接手的那次在别处接着跑完只结束一次、后面那一步只跑一次;收尾按属主写;撞号被库拒绝;多进程端到端加 6b、6c(真 SIGSTOP / SIGCONT) 2026-10-19 13:15:56 +08:00
ThearchyHelios 75ab3678cb 代码里拦住新旧版本混跑(用户拍板):新增 cluster/version——代码版本(包版本 + 构建号 AGENTLAB_BUILD 或 git 提交 + app/ 下源码指纹,比较按源码指纹)、库结构版本(各表各列加迁移清单的哈希),进程登记时一并记下(cluster_workers 两列,add-only 迁移)。PostgreSQL 时补列之前先看一眼(preflight):库里还有活着的、版本不同的进程,心跳在走就拒绝启动、照实写明是哪几个进程什么版本、要先停掉再升级,心跳停着的(强杀留下的)等租约过期再起;登记那一下在事务级咨询锁里再查一遍,两个不同版本同时启动只有先登记上的起得来。Docker 镜像带上构建号;README 写明升级步骤。补测试:版本不同的活进程被点名拒绝、同版本照常加入、过期的不算、只比源码指纹;PostgreSQL 上心跳在走的拒绝、心跳停着的等过期、登记时再拦一次 2026-10-19 13:04:07 +08:00
ThearchyHelios d68ca9774f 加直连地址 AGENTLAB_DATABASE_DIRECT_URL 和 PgBouncer 事务模式开关 AGENTLAB_DB_PGBOUNCER(用户拍板):依赖会话状态的连接——收发进程间通知的那一条(LISTEN)、跨进程的锁(会话级咨询锁,另建一个直连的小池子)、断点库(缺省)——走直连地址,普通查询走 AGENTLAB_DATABASE_URL,不设就全用同一个;开关打开时普通地址不用客户端连接池、关掉 SQLAlchemy 和 asyncpg 的预备语句缓存、预备语句用随机名字(照 SQLAlchemy 文档),事务级咨询锁照常成立;开关打开却没给直连地址时拒绝启动。README 写三种部署(直连、PgBouncer 会话模式、事务模式加直连地址)和要配的 server_reset_query,照实说没在真的 PgBouncer 上跑过。补测试:地址解析和规范化、断点库缺省走直连、事务模式关掉的几样、LISTEN 和跨进程锁走直连、事务模式没给直连地址拒绝启动 2026-10-19 13:01:21 +08:00
ThearchyHelios 01af07b193 出具、按需视图的每日上限改成先占额度再发起(用户拍板):新增 cluster/quota——额度记在库里(rate_counters 按名字 + 本地日期一行),占一份是一句带条件的 UPDATE(没到上限才加一),两种库上都是原子的,这一天第一次占按库里已有的记录起算,发起被拒或出错就退回。出具去掉全站一把锁,只留同一(运行、工作流、版本)的去重锁,几份不同的出具可以同时发起;按需视图的锁缩回按缓存键(视图 + 参数)去重,每日上限改用这个应用的额度。补测试:20 个协程同时占正好到上限、按已有记录起算、退回再占;两个进程同时占正好到上限;三份不同的答案同时出具正好到上限、多出来的回 429 2026-10-19 12:57:38 +08:00
ThearchyHelios 6ed782a84b 运行名额改成给交互留底、其余可借(用户拍板):交互留底缺省全站上限的 1/4、至少 1、至多全站上限减 1,应用、定时、系统三类合起来永远用不到留底;三类各自的上限缺省 = 全站上限 − 留底(设置里可调小),没人问数据时评测能开满;交互上限缺省 = 全站上限;等名额照旧按优先级、同级先来先得。存着的设置原样存、缺省按全站上限和留底现算;留底不小于全站上限时 422。设置页「运行并发」加「给交互留底」一项,写明留底和借用是什么,README 同步。补测试:缺省值、空闲时系统类借满到 全站 − 留底、留底不借给应用类、问数据一来马上拿到留底;多进程端到端加 5b(评测借满时问数据拿留底、不等评测跑完) 2026-10-19 12:53:28 +08:00
ThearchyHelios 319b787688 合入 nr8/l 的 e1ff1c90(问数据事件日志清理不给时间时按当前时间算)
# Conflicts:
#	backend/app/chat/log.py
2026-10-19 12:48:42 +08:00
ThearchyHelios e1ff1c9070 问数据事件日志的清理那一拍不给时间时按当前时间算:调度循环的 process_due 不一定给 now,chat/log.purge_tick、purge 以前拿 None 去减保留期就报错(多进程端到端里查出)。补测试 2026-10-19 12:37:30 +08:00
ThearchyHelios e6a3ee8f95 转发运行事件时跳过不认识的事件种类(回放照样读得到);test-multiprocess.sh 不带参数时 macOS 的 bash 3.2 报 args 未定义,参数直接原样交给 pytest 2026-10-19 12:30:30 +08:00
ThearchyHelios 4e3623885b 合入 W2-a 的复核修复(nr8/a:导入的 NOT NULL 补值与孤儿行、收尾 dispose、sslmode 换算、PostgreSQL 写入去 NUL、不分大小写搜索 contains_ci、json_eq 两库同语义、JSON 守卫、用户可见列表补决胜键、bubblewrap --clearenv、部署脚本与原子写的几处、README 连接数预算)
# Conflicts:
#	backend/app/api/schedules.py
#	backend/app/main.py
2026-10-19 12:21:38 +08:00
ThearchyHelios 89cd135174 补多进程协调的单测(两种库):别的进程用库里的行装出来(登记着的同伴、从没登记过的已经没了的进程)——谁还活着、名额按优先级先给交互类、一类到了上限不挡别的类、没了的进程占着的名额收回而活着的同伴的不碰、同源队几个进程共用且跳过没了的进程的位置、接手运行只碰属主不在了的(升级前没记属主的照不在了处理)、停止和记事件交给活着的属主、属主不在了的停止直接接手放弃、当班到期交接、同一本每日账并发记不越过上限、SQLite 第二个进程(以及 AGENTLAB_WORKERS 大于 1)拒绝启动;评测说明里的并发一段照现在的名额说 2026-10-19 12:14:39 +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 5272d8f028 知识库「同时只跑一个重建」的两条测试,放行之后只重建一个空集合:测的是互斥不是重建本身。按全部集合重建要把同一个 xdist 进程里别的测试留下的几百段都重算一遍(这一轮加了测试,分到它那个进程的多了,实测停在 428/431),满载时超过 10 秒的等待,后面一条也跟着撞上「正在重建」 2026-10-19 12:07:31 +08:00
ThearchyHelios db328efd21 原子写和部署脚本的几处(复核 R-a11、R-a12、R-a13 追加写)
- R-a12 create_bytes:硬链接不了的文件系统(exFAT、一部分 SMB / FUSE,EPERM / ENOTSUP / EXDEV)不再首次启动就崩,退回 O_CREAT | O_EXCL 直接建(仍然只建一次,说明里写了写的那一会儿读的一方可能读到不完整);建成后 fsync 目录(同 raw_store)
- R-a13 file_write 的追加改回原地追加写(O_APPEND,core/atomic.append_bytes):不换文件(inode、权限、开着的句柄不变),原有内容不动,文件大了也不用整份读出来重写;取舍写在函数说明里——读的一方最多看到半截新内容。覆盖照旧先写临时文件再改名,并沿用原文件的权限
- R-a11 deploy.sh 改属主前认数据目录收紧:只认 agentlab.db、.secret_key、.agentlab-data 三样之一(不再认 uploads/ 这种普通目录名);.agentlab-data 是服务启动时(Settings.ensure_dirs)建的标记,只建一次不覆盖,库在 PostgreSQL、密钥由环境变量给的部署也认得出;老部署有 agentlab.db 或 .secret_key。deploy/README 写明这个文件别删
- 测试:模拟不能硬链接仍只建一次、权限 0600、不留临时文件;覆盖沿用原权限;追加不换 inode、权限不变;file_write 追加不换文件、覆盖照常;数据目录里有标记、重复启动不覆盖
2026-10-19 12:07:31 +08:00
ThearchyHelios ba87a93ef7 bubblewrap 沙箱不再继承后端的环境变量(复核 R-a5):bwrap 参数最前面加 --clearenv,再按缺省(HOME、TMPDIR、PATH、LANG、PYTHONDONTWRITEBYTECODE)和调用方给的逐条 --setenv;bwrap 进程本身也只拿 PATH
以前被执行的代码看得到后端进程的全部环境变量:模型的 API Key,现在又多一条带密码的 AGENTLAB_DATABASE_URL。local、seatbelt 一直只给最小的一套。调用方给的变量以前插在最前面、会被缺省的盖掉,现在放在最后、能盖过缺省的,同另外两种沙箱。测试(本机没有 bwrap,测参数和进程环境的组装):--clearenv 在所有 --setenv 前面,AGENTLAB_* / *_API_KEY 的名字和值都不出现,bwrap 进程的环境只有 PATH
2026-10-19 12:07:31 +08:00
ThearchyHelios 0d9f1d9339 用户看得到的列表补决胜键(复核 R-a9):按名称、时间等可能并列的排序后面补上同一个模型的 id,并列时两种库排出来一样
- 实测 /api/evals/calibers、/api/schedules/trigger-options 按 Workflow.name 排序遇同名并列时 SQLite、PostgreSQL 顺序不同。用 AST 逐个过了一遍 order_by:最后一个排序键是 created_at / updated_at / last_active_at / at / name / 各种 *_at 之类、不唯一的列,又不带 DISTINCT、GROUP BY 的,补「, 模型.id」(降序补 id.desc()),共 104 处,分布在 api、apps、auth、blueprints、chat、data、engine、eval、ledger、look、memory、process、providers、scheduler(runs.py 里的三处在上一个提交里)
- 按唯一列(seq、version、唯一的 name)排的不动;按聚合、coalesce 之类表达式排的说明见 db/postgres
2026-10-19 12:07:06 +08:00
ThearchyHelios 7febf2bcdb 两种库行为再对齐一轮(复核 NUL、R-a4、R-a6、R-a7、R-a10)
- 编排者的决定:PostgreSQL 下文本列写入时去掉 NUL 字符(before_cursor_execute 钩子,只装在应用库引擎上,看所有字符串参数,没有 NUL 的原样交回),SQLite 不变;同 JSON 列的处理
- R-a4 应用库地址里的 sslmode= 换成 asyncpg 的 ssl=(取值同一套),sslrootcert 等证书参数、application_name 这类 asyncpg 不收的参数启动时就报错并说怎么写(证书用 PGSSLROOTCERT 等环境变量);断点库连接串换回 sslmode=
- R-a6 不分大小写的搜索换成 db/portable.contains_ci:SQLite 上同 ilike(lower LIKE lower),PostgreSQL 上模式带 COLLATE "default"(列是 COLLATE "C",列上的 ILIKE 只认 ASCII,É/é、Ж/ж、全角A/a 匹配不上);运行列表按名字、对象索引按注释两处都改;改正 db/postgres 里那句说明
- R-a7 JSON 守卫改成编译层:tests/jsonguard 挂在应用库编译器上(conftest,两种库、跑全量时一直生效),整个 JSON 值出现在 = / != / IN / IS DISTINCT FROM / 大小比较、SELECT DISTINCT、GROUP BY、ORDER BY、UNION(去重的几种)里就报错;按类型认,变量别名、跨行 order_by、select(Run.origin).distinct()、JSON 下标的比较都抓得到,测试拿这些反例证明,json_eq、IS NULL、UNION ALL 不受影响。原来的逐行正则测试删掉
- R-a10 json_eq 两种库同一语义、按 JSON 类型比:字符串只等于字符串,数只等于数(1 等于 1.0),True / False 只等于 JSON 的 true / false(SQLite 上用 json_type 分开,以前 1 能匹配 true);非标量 TypeError。json_text 两种库都是「字符串取本身、别的取 JSON 写法」(SQLite 上同 PostgreSQL 的 ->>),数 1 的 json_text 两边都是 '1'
- db/postgres 说明里写清 NULL 排序补写的范围(只认直接按列排的)
2026-10-19 12:06:31 +08:00
ThearchyHelios 0e997eb968 copy-to-postgres 在真实开发数据上核对不过的几处(复核 R-a1、R-a2、R-a3、R-a8、R-a13)
- R-a1 老库 NOT NULL 列为空:第一版补 schedules.trigger 时没带缺省值,存量定时任务这一列是 NULL,导入 PostgreSQL 撞 NOT NULL,连带触发记录、通知撞外键。迁移表里这一列改成带 DEFAULT '{}';新增 _NOT_NULL_BACKFILLS,启动时按模型的缺省值把已经补过、留着 NULL 的填上(SQLite 这边也填,两种库存的一样;只更新这一列,不碰 updated_at);导入时 _Fixer 遇到 NOT NULL、有缺省值的列的 NULL 也填缺省值,计入「转换」。迁移表里的 NOT NULL 列都过了一遍,只有这一列没带缺省值
- R-a2 孤儿行:导入前在快照上按模型外键扫(settle_orphans):外键是 SET NULL、列可空的置空,计入转换;CASCADE / 不可空的从快照里拿掉、不导入,反复扫到没有为止,报告里单列「孤儿行(SQLite 当时没强制外键)」的表和条数,不算核对失败
- R-a3 停服务后 agentlab.db-wal 还在:lifespan 收尾 dispose 应用库引擎(只加了这几行),SQLite 最后一个连接关掉时并回、删掉 -wal,PostgreSQL 的池子也正常关
- R-a8 自增主键的序列取「目标表 MAX、快照 sqlite_sequence 的计数器、序列现值」三者最大,删过的号不复用(召回按 source_changes.seq 当游标)
- R-a13 插不进的行的原因不再带「<class 'asyncpg.exceptions.…'>:」前缀(errors.first_line 两种写法都去);设了 AGENTLAB_DATABASE_URL 却没装 [postgres] 时,应用库引擎和断点库都直接说要装什么
- 测试:DROP COLUMN 再按第一版迁移补回造老表、关着外键写孤儿行,迁移填值、快照上置空和拿掉、导入 PostgreSQL 核对通过且重跑一样;NULL 落回模型缺省值;端到端里删掉最后一条变化,导过去新变化从 3 编起;起停一次服务后数据目录里没有 -wal / -shm(去掉 dispose 这条测试就挂)
- PostgreSQL 引擎上另挂了去掉文本参数里 NUL 的钩子(db/postgres.strip_nul,见下一个提交)
2026-10-19 12:06:31 +08:00
ThearchyHelios ae254b052e 合入遗留收口分支 nr8/l 的复核修复(变化记录先占住那一行再读改写、召回里行序不定的指标、事件触发列表按任务各取上限、选对象按名字查用 ilike、子工作流写入认旧键、几处测试的竞态)
# Conflicts:
#	backend/app/ledger/recall.py
2026-10-19 12:05:19 +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 b1736095a0 结果未知自动核实的测试先等排上查询再看记录:运行先挂起、runner 再安排核实(actions.on_unknown),并行跑时测试会在中间读到还没排上查询的记录。测试的竞态,产品行为不动 2026-10-19 11:58:45 +08:00
ThearchyHelios b23784d65b 动作确认的测试先等运行停到确认上再去确认:待办和审批同一个事务开出来,那一刻运行可能还没收成 interrupted,PostgreSQL、并行跑时偶发「运行正在运行,没有待处理的审批」。测试的竞态,产品行为不动 2026-10-19 11:54:48 +08:00
ThearchyHelios b672088fe3 召回里行序不定的指标不当「没变」(编排者拍板):全部指标都行序不定的,结论写「核对不了(行序不定)」(召回批次的新状态 row_order),开召回待办请人核对,待办和通知的标题照实说没能核对,不在原答案上记「已核对,不影响」;部分行序不定的,已判定的照常判,行序不定的那几项在结论里列出(row_order_metrics),数没变时原答案的记账照样列出、问数据的轮次写「其中「x」行序不定,没能核对」。补测试 2026-10-19 11:54:08 +08:00
ThearchyHelios c768c56fd7 多进程协调补齐几处:执行时长从拿到名额算起(排队等名额不算执行,墙钟本来就从开始执行算);蓝图留痕、蓝图助手开轮先占住那一行再取最大值往下接;问数据等别的进程接着跑的运行时回库里等封存;按配方导入的 AI 起草、知识库重建索引另取跨进程的锁(多进程时重建进度记在设置表里,别的进程读得到、属主不在了照实说没做完);调度循环一拍的间隔可配(AGENTLAB_SCHEDULER_TICK_S) 2026-10-19 11:51:29 +08:00
ThearchyHelios 4ffd9ad431 变化记录的 affects 先占住那一行再读改写(复核 L5):口径试算记没试算的那几版(ledger/recall._probe_skipped)和探查刷新影响面(data/source_changes.record)以前都是先读再整份写,交错时互相盖掉。现在两处都先发一句按条件的 UPDATE(record 顺手记又见到一次,SQLite 上拿到写锁、PostgreSQL 上锁住这一行),再读出来改。补并发测试(六版口径同时记、探查同时刷新,一条不丢) 2026-10-19 11:48:43 +08:00
ThearchyHelios 4548e8bd25 列表上「有几条在等」按任务各取各的上限(复核 L4):等着的事件按任务、还没派发的事件按(事件种类, 对象)用 ROW_NUMBER 各取前 N 条(同改前每个任务各读的那么多),不再所有任务合起来一个上限——积压多的任务会把别的挤掉,它们的 due_at 为空、未派发数少算。补测试 2026-10-19 11:45:55 +08:00
ThearchyHelios 20f8eb37e0 选对象按名字查改用 ilike(复核 L3):PostgreSQL 上 LIKE 分 ASCII 大小写、SQLite 不分,两种库说法不一;% 和 _ 照 runs._like 转义、按字面匹配。补测试 2026-10-19 11:44:49 +08:00
ThearchyHelios c59b085922 子工作流里的写入跨升级认旧键时按事件和内容认是谁的、是哪一笔(复核 L1、L2):升级前子图里的写入按子图里的 id 记键,和父图同名节点的键一样。以前父图有同名节点时一律不认旧键:子图里结果未知的那一笔核实为已生效后接着跑,用新键又发一笔;父图那个节点按自己的键找到子图那一笔、交回它的回执,自己那笔一直发不出去。现在一条记录是哪个节点写的按它的 action.* 事件上记的节点 id 认(认不出的按能力和内容指纹):按自己的键找到别人那一笔的换一个只属于自己的键;认旧键时还要内容指纹是这一次的——跨升级的循环第二轮按老算法同样是第 1 次执行,找到的是第一轮那一笔,金额不同就照常发,不再记「已经生效」。去掉不再用的最外层节点 id 传递;改对两处过时的说明(审批恢复时子图从自己的断点接着跑;终态事件的途经驳回含子工作流里的)。补跨版本测试:同一个进程里先装成升级前的代码跑到挂起、再换回现在的代码接着跑 2026-10-19 11:43:41 +08:00
ThearchyHelios 87f0d62f9b 多进程协调(W2-b)第一步:新增 app/cluster——工作进程在库里登记、心跳续租约(属主随进程,进程没了它认领的行一起到期),调度当班的租约,发给属主进程的停止 / 记事件请求,PostgreSQL 的 LISTEN/NOTIFY 叫醒,跨进程的互斥锁(咨询锁),SQLite 单进程守卫(第二个进程拒绝启动);运行、问数据一轮、起草 / 剖析 / 探查 / 评测 / 影子起草、文档、发布单记 owner,启动整理改成只接手属主不在了的行,当班进程隔一会儿再接手一次;运行的并发名额改成库里按交互 / 应用 / 定时 / 系统四类发(各有全站上限和优先级,设置里可调),替掉进程内的信号量;同源队记在库里;运行停止、记事件跨进程交给属主;运行事件、问数据事件跨进程转发(库里按 seq 追,不落库的流式增量和保活心跳只转给在看的进程);每日花费账先占住那一行再读写;访问密钥限流、登录失败计数在 PostgreSQL 时记在库里;登录设置、对外地址、向量模型、能力快照、数据源连接池、应用页面缓存跨进程失效;上传版本库、记录表、按需探查、出具、召回、补算、按需视图、个人刷新、定时发起的锁换成跨进程的锁 2026-10-19 11:40:33 +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 f0c34d790d 守着 PostgreSQL 的 json 列:扫应用代码里对整个 JSON 列做 ==、!=、in_、DISTINCT、ORDER BY、GROUP BY 的写法(json 没有相等运算符,SQLite 不报、PostgreSQL 报错),一处都不许有 2026-10-19 10:28:18 +08:00
ThearchyHelios 5e6ba12678 断点库模块去掉没用上的 kind();test-postgres.sh 的注释照现在的连接池写法改 2026-10-19 10:27:17 +08:00
ThearchyHelios b9cfc243e2 PostgreSQL 上文本按字节比大小、排序,同 SQLite:应用库建表时文本列带 COLLATE "C"(PostgreSQL 缺省按建库的区域设置比,en_US.UTF-8 下大小写混排、标点被忽略,排出来的先后和 key < '…' 的结果都跟 SQLite 不一样),不看建库时选了什么;驱动报错的第一句去掉 asyncpg 带的「<class '…'>: 」前缀
- 测试:大小写、标点、中文混在一起的排序和比较两种库一样;建表语句里带 COLLATE "C",SQLite 的不带
- README:和 SQLite 一致的那几条补上排序规则
2026-10-19 10:26:45 +08:00