合并 staging,并把长报告缓存目录登记进自行清理名单
Independent Staging Quality Gate / validate (push) Successful in 14m32s
Independent Staging Quality Gate / publish (push) Successful in 4m18s

与最新 origin/staging 合并。report_reference_cache 写入 OFFLINE_SCRATCH_NAMES。清理仍由每次读取前删掉两天前的文件完成,两个缓存模块的行为没改。

自测:test_api_scratch_retention 10、test_report_reference_perf 15、test_consult_card_full_source 12,共 37 通过。

Co-Authored-By: Grok (agent loop)
This commit is contained in:
jesse-ux
2026-10-14 10:40:43 +08:00
co-authored by Grok (agent loop)
78 changed files with 67879 additions and 18059 deletions
@@ -0,0 +1,51 @@
# PROGRESS · API 磁盘缓存留存(2026-10-14)
- 分支:`codex/api-disk-cache-retention-20261013`
- 任务书基线写的是 `77057a819`。本分支从当时的 `origin/staging` `66cd60081f37a57680274633fcb3fb942d01bb2f` 拉出。A/B 的父提交用的是这个 SHA,不是任务书里的旧基线。
- 接口文件行数:10946(验收口径 ≤ 10970)。类方法数和伪造点没有增加。
## 做了什么
- T1:新增 `scripts/api_scratch_retention.py`。启动时清理全部已登记目录,并按 `JYOTISH_SCRATCH_PRUNE_INTERVAL_SECONDS`(默认 1800,0 表示不启后台线程)周期清理。排盘缓存新文件改为仅本人可读,先写临时文件再换上。`prune_expired_async_jobs` 只留同名薄包装。
- T2:`VEDASTRO_WRITE_AUDIT_ARTIFACTS` 默认关。关掉时不写审计文件,`artifact_path` 为 `None`。打开时写紧凑 JSON,仅本人可读,先写临时文件再换上。成功快照仍用原 TTL;失败、不完整、被挡住的用短 TTL,默认 300 秒,并且不超过成功 TTL。旧缓存没有 `negative` 标记时仍按成功的长期限读。状态接口改报含回落的成功期限,并多报失败期限。`.env.cn.example` 只加了注释,两个 604800 没改。
- 成功的判据:`available is True` 且 `status == "ok"`。`partial` 即使 `available` 为真也算失败缓存。
- T3:年月日能整除才收成整数,不截断 1990.5。时分秒和经纬度、时区能解析成有限数字就收成浮点,不四舍五入。解析不了的保持原值。日期取前 10 位,空值仍是空值。缓存格式版本 5 → 6。快速排盘和完整排盘仍是两把键。
- T4:前台快照、负缓存、网关任务、分盘段都进了登记表。只删符合原文件名的过期文件。网关排队中和进行中的不删。读写逻辑和键没改。
- T5:脚本在 `scripts/research/api_disk_cache_ab.py`,逐字节比较在 `scripts/research/api_chart_cache_byte_diff.py`。记录在 `docs/testing/api-disk-cache-retention-ab-20261013.md`。
- T6:没有改咨询卡片缓存。数字用任务书 §2.5,没有重测:未命中构建 1.9 秒;文件 5097751 字节;命中时解析中位 68.5 毫秒;整次命中 82.5 毫秒;两天大约每个活跃用户 10 MB。可选方向仍是两条:按领域切片只读需要的部分;清理改为每隔几分钟一次,而不是每次读取都扫全目录。没有做进程内已解析包缓存。
- T7:BUG-1330、BUG-1331、BUG-1332。变更说明一句。任务索引改为待验收。没有改界面说明。
## 命令和结果
| 检查 | 命令 | 结果 |
| --- | --- | --- |
| 新留存、异步任务、增长合同 | `pytest tests/test_api_scratch_retention.py tests/test_api_async_job_contract.py tests/test_api_server_growth_contract.py -q` | 26 通过 |
| 安全缓存 | `pytest tests/test_api_server_security.py -q -k cache` | 6 通过 |
| 任务书列出的 VedAstro / 咨询套件 | 见任务书 §8 那一条 | 4 失败,见下。其余通过 |
| 需要审计文件的执行器测试 | `pytest tests/test_vedastro_service_adapter_executor.py::test_vedastro_range_scan_records_hashes_and_artifact_path -q` | 1 通过 |
| 逐字节比较与 A/B | `python scripts/research/api_disk_cache_ab.py` | 退出码 0。命中率 B/A = 1.333。七天后 B 剩 40 个文件,等于当天键数。审计文件 0。负缓存剩 1。一万个文件的清理 20.174 秒 |
| 接口行数 | 按换行计数 | 10946 |
既有断言改动只有一处,在 `tests/test_vedastro_service_adapter_executor.py`:原值是子进程沿用进程环境;新值是显式打开审计落盘;原因是默认关闭后这条测试仍要检查文件存在。这是测试前置,不是放宽断言。
## 未达到的目标(目标不改)
- 混合写法再重复 3 次时,命中率只是 A 的 1.333 倍,不是 2.5 倍。重复本身已经让 A 命中三分之二。
- 一万个过期文件的清理用了 20.174 秒,不是 2 秒内。清理不在请求线程。默认间隔和失败短期限没有因此改掉。
## 本机套件里原先就会红的三条
- `tests/test_vedastro_gateway.py` 要求原始响应文件权限是 0600。Windows 报出来的是可写,不是 0600。这条断言没改。新测试在 Linux 上仍检查 0600,Windows 上只检查文件写出来了。
- `tests/test_vedastro_runtime_ops.py` 要求已安装的 VedAstro 是 1.23.25,本机是 1.23.30。与这次缓存改动无关。
- `tests/test_three_engine_parity_runner.py` 的公开盘回放把 PyJHora 记成 raw_imported,不是 structured_captured,同时在下载星历。运行器没改。
## 环境缺口
- 生产和测试环境里成功缓存的实际秒数,这份仓库读不到。部署后看状态接口的两个期限数字即可。
- 生产卷上已经堆了多少文件,这里不知道。
- 主测量挡住了 VedAstro 导入。本机有 SDK,官方端口能连通。不挡 SDK 的探针仍关闭外网取数,一次完整排盘 4.167 秒,没有报错,没有拉真实快照。
## 未做
- 没有改部署文件、生产环境变量、数据库,也没有手工清生产卷。
- 没有把咨询卡片缓存并进周期清理。
@@ -0,0 +1,70 @@
# PROGRESS · 流式回答时侧栏不再跟着每帧重画(issue #59)
- 分支:`codex/home-sidebar-rerender-20261013`
- 实际基线:`origin/staging` `66cd60081f37a57680274633fcb3fb942d01bb2f`
- 任务书基线写成 `77057a819`,计划评论里的 base 是 `2994588ad4d858dead4835943e5883c5aa2b03f8`。开工时远端 staging 已是上面的 `66cd6008`。A/B 就跑在这个提交上,没有另开只读工作树(本轮不能离开当前工作树)。方向没有改,不需要拍板。
- `docs/BUG_HISTORY.md` 在这个基线上停在 BUG-1322。BUG-1323~1328、1345、1346 属于还没合入的别的分支,本单只用 BUG-1329。
- 未改 `page.tsx`。没有运行时开关。没有启用 React Compiler。Skill 版本不变。浏览器 A/B 未跑。
## 做了什么
外壳拿到的点击函数不再每次渲染换新,点下去仍执行首页刚渲染的那一版。注册只在数据变了才发给侧栏:会话行要逐条还是同一个对象才算没变,没变就不重建行。可见会话按当前人物记忆。侧栏自己的上下文对象也不再每次新建。卸载首页时仍会清掉注册。
## 断言三栏
| 位置 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `frontend/tests/session-list-lifecycle.test.tsx` 外壳「打开资料」函数 | `assert.notEqual(onOpenProfile, initialCallback)` | `assert.equal(...)`;再改一版后仍是同一个函数,调用记录从 `[1]` 加强到 `[1, 2]` | 包装函数身份稳定。调用必须落到最新一次渲染,不能只删掉「不相等」 |
`HomeProbe` 仍是每次渲染新回调、新数组,没有改成常量。
## 基线失败(改代码之前,同一测试,3 次,退出码都是 1)
失败停在 `assert.equal(duringFrames.registers, 0)`,实际是 60。60 帧里侧栏提交也是 60。换当前项、改标题、换人各注册 1 次;只改回调版本也会再注册 1 次。剔除函数后的内容摘要:
| 档 | 60 帧注册 | 60 帧提交 | 60 帧耗时三次(毫秒) | 中位 | 内容摘要 |
| --- | --- | --- | --- | --- | --- |
| 30 条虚构会话 | 60 | 60 | 2774.964 / 2778.961 / 4202.085 | 2778.961 | `b18f05a3d83be5b41584787b7c0495f1fcec8ef7b8ecfbdbb3c083c40796c103` |
| 100 条虚构会话 | 60 | 60 | 10530.828 / 11799.253 / 12284.103 | 11799.253 | `cef0a63d6f3fe72e541f9ac882b8eaf305b6933fdd07ca3002e8cd03bb139d25` |
更早一次探针把注册函数也做成每次渲染新建,60 帧数到 120 次注册、60 次提交。那是清理函数跟着新函数又清了一次,不是产品路径。交付用的测试和生产一样,用提供者给出的稳定注册函数,所以改前是 60 而不是 120。
## 改后(同一测试,3 次,退出码都是 0)
| 档 | 60 帧注册 | 60 帧提交 | 60 帧耗时中位 | 换当前项 | 改标题 | 只改回调版本 | 换人 | 内容摘要 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 30 | 0 | 0 | 0 | 注册 1、提交 1 | 注册 1,标题更新 | 注册 0,调用记到第 4 版 | 注册 1,列表换成另一人 | 与改前相同 |
| 100 | 0 | 0 | 0 | 注册 1、提交 1 | 注册 1,标题更新 | 注册 0,调用记到第 4 版 | 注册 1,列表换成另一人 | 与改前相同 |
三次摘要都与上表相同。门槛达到:60 帧内注册 0、侧栏提交 0,内容摘要逐字节一致。
## 自测
| 检查 | 命令 | 结果 |
| --- | --- | --- |
| 类型 | `node frontend/node_modules/typescript/bin/tsc --noEmit -p frontend` | 退出码 0 |
| 规范 | `npm run lint --prefix frontend` | 0 error,126 条原有 warning。本单文件没有新增 warning,没有 `eslint-disable` |
| 定向测试 | `tsx --test` 下表 10 个文件 | tests 94,pass 94,fail 0,cancelled 0 |
| 数据库 | 未跑 | 本单不碰数据库 |
| 浏览器 | 未跑 | 浏览器 A/B 未跑。步骤在 `docs/testing/home-sidebar-rerender-20261013.md` |
| 隐私标记 | `.venv\Scripts\python.exe -m pytest tests/test_repo_privacy_markers.py -q` | 通过 |
定向文件:`home-sidebar-rerender`、`session-list-lifecycle`、`session-list-provider`、`sidebar-contract`、`sidebar-state`、`secondary-page-entry`、`account-dialog-inert-20260918`、`home-shell-growth-contract`、`home-streaming-render-split`、`chat-profile-picker`。
全量 `npm test`、`next build`、Python 快速门未跑,留给验收。
## 2026-10-14 修复单
按修复单合并了最新 `origin/staging`。只改了 `frontend/tests/chat-navigation-a11y-contract.test.ts` 里账户菜单「充值」那一条源码断言,改成认稳定包装的写法,仍然要求打开 billing 且来源是 `account-menu`。业务代码没有改。
又搜了一遍 `onOpenProfile`、`onOpenGeneral`、`onOpenLogout`、`onNewChat`、`onSelectSession`、`onLoadMore`。测试里其余命中的是侧栏组件自己的入口,或校正点数不足时打开充值,不是这条旧写法,没有改。
和上一版 `63509431` 比,网页业务目录里多出来的只有合并测试线带入的校正提速(`engine-client.ts`),不是这单写的。这单自己的提交不碰 `frontend/src`。
| 检查 | 命令 | 结果 |
| --- | --- | --- |
| 类型 | `tsc --noEmit -p frontend` | 通过,退出码 0 |
| 规范 | `npm run lint`(在 frontend) | 0 error,125 条原有 warning。本单改的测试文件没有新增 warning |
| 这条旧检查 | `tsx --test tests/chat-navigation-a11y-contract.test.ts` | 13 通过,0 失败,0 取消 |
全量 `npm test` 仍留给验收。
@@ -0,0 +1,73 @@
# 进度 · 服务器内存与数据库往返(2026-10-13)
issue #58。分支 `codex/node-runtime-resources-20261013`。
2026-10-14 按修复单把往返对照脚本从 `frontend/scripts/bench-local-pg-roundtrips.ts` 挪到 `frontend/tests/bench-local-pg-roundtrips.ts`。文件名不是 `.test.ts`,全量测试不会自动收进去。业务代码没有改,对照数字没有重跑。原任务书里的旧路径保持不动。
任务书基线写的是 `77057a819`,计划评论里的基线是 `2994588ad4d858dead4835943e5883c5aa2b03f8`。本分支实际从当时的 `origin/staging` `66cd60081f37a57680274633fcb3fb942d01bb2f` 拉出。没有因此停下来问产品,改动仍按任务书做。
## 做了什么
- 报告工人的等待:计时器到点就摘掉取消监听。引导打分里同一段等待也摘掉。空转不再往进程上堆监听。
- 本地数据库:列、主键、函数签名缓存 300 秒;设置角色和两条身份合成一条语句。开始和提交仍分开。两个开关默认打开,写成 `off` 时语句顺序与改前一致。
- 三张内存表:交付记录超过 60 秒删除,最多 1 万条;重算记录超过 6 小时删除,最多 5 千条;限流按见过的最大窗口清理已出窗的键。
- 登录读缓存:只有 `IDENTITY_SESSION_COOKIE_CACHE=on` 才缓存 300 秒。默认关闭。
## 不做的
只读、又没有身份时省掉事务:不做。那种做法只能用会话级角色,归还连接前再清。往返数不降,而且一旦没清掉,下一次请求会带着上一次的角色。违反「连接还回池子时不能带着角色或身份」。
`begin` 没有并进一条多语句查询。
## 语义变化
同一道校正题、同一份证据,6 小时后或因为超过 5 千条被挤出后,可能再重算一次。这比「进程重启后才会再算」更收敛。60 秒内的交付去重、窗口内的限流允许或拒绝,都没有改。
## 基线失败
修之前的等待写法,在第 200 次空转时取消信号上还有 199 个监听。同形脚本输出:`listenersAt200=199`,`assertion failed: 199 !== 0`。修之后的测试断言是 0,并且通过。
## 登录读取的调用点
敏感,每次跳过缓存:
- 改密码:`frontend/src/app/api/account/password/route.ts`
- 注销账户:`frontend/src/app/api/account/deletion/route.ts`
- 全部后台入口:`frontend/src/lib/admin/auth.ts`
其余业务接口走 `createServerSupabaseClient()`,不带跳过参数。开关打开后,这些普通读取可以走 300 秒缓存。
改邮箱、两步验证、后台插件自带的敏感入口本来就会重新读库,这次没改。咨询里检查「正在注销」的那次调用,以及后台查封禁的语句,都没有改成缓存。
## 对照结论
详见 `docs/testing/node-runtime-resources-ab-20261013.md`。两个数据库开关一起:往返 49 → 32(低于 70%),耗时中位数 75.84 → 36.48 毫秒(下降 51.9%),返回内容一致。`npm run test:db` 开关关、开关开各一轮,都是 81 项、通过 68、失败 13、取消 0。失败名称与 `tools/agent-loop/windows-known-failures.txt` 的 13 条相同,没有多出来的。运行器因此退出码是 1,这 13 条是 Windows 上原有的。两个数据库开关默认打开。
登录读缓存的查库次数在测试里从 3 降到 1,但没有对真实身份库做耗时对照,默认保持关闭。要打开,把 `IDENTITY_SESSION_COOKIE_CACHE` 设成 `on`。
网页容器已经用 env 文件读环境变量,所以这三个名字不必改 Compose。
## 自测
| 检查 | 命令 | 结果 |
| --- | --- | --- |
| 类型 | `tsc --noEmit -p frontend` | 通过,退出码 0 |
| 规范 | `npm run lint`(在 frontend) | 0 error,125 条原有 warning,未改 |
| 本单测试 | `tsx --test` 任务书点名的文件加登录缓存测试 | 134 通过,0 失败,0 取消 |
| 真库身份 | `database-local-postgres-session-setup.test.ts` | 1 通过。事务内角色和身份生效,连接归还后再借出时身份已空 |
| 数据库套件 | `npm run test:db`,两开关先关后开 | 各 81 / 通过 68 / 失败 13 / 取消 0,名称与已知清单一致 |
| 往返对照 | `tests/bench-local-pg-roundtrips.ts`(按修复单从 `scripts/` 挪来) | 见上,`payloadMismatch` false。数字未重跑 |
没有跑前端全量 `npm test`、Python 快速门、`next build`。生产内存曲线要等部署后看。真机两台设备改密码的步骤在 `docs/testing/node-runtime-resources-20261013.md`,登录缓存默认关着,那份清单的第 2 步要先把开关打开才看得到。
## 2026-10-14 修复单
按 `docs/tasks/TASK-node-runtime-resources-fix-20261014.md`:先合并最新 `origin/staging`,再把对照脚本挪进测试目录。业务代码没有改。对照数字没有重跑。
和上一版 `4c3485bc` 比,网页业务目录里多出来的只有合并进来的校正提速改动(`frontend/src/lib/rectification-agentic/v9/engine-client.ts`),不是这单写的。这单自己的提交不碰 `frontend/src`。
| 检查 | 命令 | 结果 |
| --- | --- | --- |
| 类型 | `tsc --noEmit -p frontend` | 通过,退出码 0 |
| 规范 | `npm run lint`(在 frontend) | 0 error,125 条原有 warning,未改 |
| 镜像导入守卫 | `tsx --test tests/runtime-sources-no-test-imports.test.ts` | 2 通过,0 失败,0 取消 |
@@ -0,0 +1,97 @@
# 校正打分提速进度(2026-10-14)
结论:两小时窗口的打分大约快到原来的 38%,结果不变。11 个场景的规范化输出与基线逐字节相同。密封重跑 20 例的 trials、metrics 与历史比较和 2026-10-08 那份记录逐字节相同,`changed_trial_count` 仍是 8。报偏移 900 例的核对写在文末。
## 基线
| 项 | 值 |
| --- | --- |
| 任务书基线 | `77057a819` |
| 计划评论里的 base | `2994588ad` |
| 本分支实际起点 | `74384be0243b16e7a261c2afdea2ca12bab92285`(当时的 `origin/staging`) |
| 冻结文件相对 `77057a819` | `git diff --stat` 为空,所以计时和逐字节对照仍用这份基线 |
机器:13th Gen Intel Core i5-13400F,16 逻辑处理器,Windows。同一进程里先跑基线 5 次再跑新代码 5 次,取中位数。`PYTHONHASHSEED=0`。绝对秒数比任务书写的 3.8–4.8 秒高,因为那组数字不是这台机器测的。下面的比例以这次同机对照为准。
## 同机耗时(5 次中位数)
| 窗口 | 候选 | 基线 | 现在 | 相对基线 | 目标 |
| --- | --- | --- | --- | --- | --- |
| 12:00–12:20 | 21 | 0.5359 s | 0.3185 s | 59% | 不慢于基线 +5% |
| 11:45–12:15 | 31 | 1.9700 s | 0.8696 s | 44% | — |
| 11:00–13:00 | 121 | 10.6181 s | 4.0695 s | 38% | ≤ 45% |
| 全天 `block_scan` 步长 10 | 144 | 6.7187 s | 3.8025 s | 57% | 不慢于基线 |
121 候选分段(中位数,秒):
| 段 | 基线 | 现在 | 相对 |
| --- | --- | --- | --- |
| `guided_collect_windows` | 4.8700 | 0.6116 | 13%(目标 ≤ 25%) |
| `merge_transition_proximity` | 1.7124 | 0.4497 | 26%(目标 ≤ 35%) |
| `get_current_narayana_dasha` | 0.7562 | 0.0387 | 探针路径仍会调用,打分循环为 0 |
| `derive_functional_benefic_malefic` | 0.3295 | 0.0081 | 一次打分 121 次,每个候选 1 次 |
| `build_candidate_static_context` | 0.9830 | 1.0625 | 这里多算了两份缓存,总时间仍下降 |
121 候选默认响应的规范化字节:基线 2,071,995(响应里带着矩阵),现在 930,631(约 0.89 MB)。目标 ≤ 0.96 MB。
## 11 个场景 sha256
两边都用 `PYTHONHASHSEED=0`,`sort_keys=True`,去掉 `column_compare_ms`。打分场景打开 `include_internal=True`。诊断场景另外去掉 `candidate_decision_receipt`,因为新诊断不再重复那份内部回执。基线工作树是一次性检出 `77057a819`,比完已删除。
| 场景 | sha256 | 字节 | 相同 |
| --- | --- | --- | --- |
| 12:00–12:20 | `2bc6c777ac4957ce99277649879f7f8ded5c8f246361d73cf18454a3ac7466b0` | 429250 | 是 |
| 11:45–12:15 | `f886afac4b27a8a1f36c771bfdf1565e8df1f4f579d19e73288b0549a9544bda` | 597372 | 是 |
| 11:00–13:00 | `2d5dcb5cd6e92664bba692d59f75eabdc4b55f822817b7a6f5106c89fd8c8708` | 2071995 | 是 |
| 23:20–00:40 | `73aeb9b7a4d0a3a2b5643aff5e2ef779f15e2e765eefc60aa3985b347ca4b9c1` | 1255752 | 是 |
| declined relationship+career | `9e48c7cf4b21c133bb52b85e73b0ab7891826a0125a5ef428f6a280503585ee8` | 1082766 | 是 |
| refresh probes + column times | `7c977c19c48448e92a7845225ba04897359f29bbaf92e4ff2c69a83e7b070b1a` | 932456 | 是 |
| 10:00–13:00 步长 2 | `e03adc5cd88e4df144186afc88cead358b67db37784717e8331f256507357cdc` | 1405125 | 是 |
| block_scan 全天步长 10 | `38b27ab49744a7a8036017d10e919f2b8b8baa58fd53590e4b0a35d9689eb1e9` | 394426 | 是 |
| block_scan 10:00–14:00 步长 5 | `6c13482afd5b5de9545185b3c92145f40629550556b2f0e83b009e690d933133` | 129483 | 是 |
| 记忆化测试的公开请求 | `e0eb1c449a2a42cd081b15af5dece3f97fcffae627ab605d9514b413617964a7` | 90384 | 是 |
| diagnostics 11:00–13:00 | `5a9d9ad7304ac01419ba85b6a24c23d1bc9b00ec1df417a7bb9385ce8dfea83b` | 456088 | 是 |
## 计数与等价
- 引导窗口:一次调用里 `_context_time` ≤ 16 × 候选数。121 与 21 的次数比不超过 (121/21)×1.2。输出与基线函数副本四种形状相同。
- 换段邻近:一次调用里 `_vim_start_dates` ≤ 2 × 候选数,`_narayana_start_dates` ≤ 1 × 候选数。先按年份 1–9999 算全表,再按事件年份过滤。`event_probes.py` 里这两个函数只在年份落在窗口内时追加,空结果不依赖窗口,所以过滤后的列表与原来在窗口里现算相同。跨午夜矩阵也相同。
- 功能吉凶:一次 121 候选打分调用 121 次。放在静态上下文顶层,不进 `feature`,`feature_hash` 不变。
- 那罗延子运:打分循环(`_candidate_row`)里 `get_current_narayana_dasha` 为 0。0 到 120 岁、步长 0.01 年,缓存查找与现算相同。探针路径 `event_probes._score_year` 仍不接收这张表,所以整次打分里这个函数不是 0。这是任务书明确不改的偏差。
- 候选上限:240 和 241 通过;242 和全天步长 1 在排盘前 50 毫秒内拒绝。步长 2、5、10 的产品窗口通过。全天 `block_scan` 在没给步长时自己改成 10,不触发上限。研究脚本里的回放半径到 120 正好 241,不超限。冻结重跑不经过 `score_candidates`,上限不影响那 900 例。
超过上限时 HTTP 400,正文含 `too_many_candidates`。API 入口文件没有改,所以错误码仍是 `ERR_BAD_REQUEST`。前端把这种 400 当成坏请求,不按服务忙重试。
## 三栏
| 位置 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `tests/test_rectification_engine_memoization.py` 缓存键 | 4 个 | 6 个,加上功能吉凶和那罗延子运表 | BUG-1324 |
| `tests/test_rectification_v5_services.py` 矩阵断言 | 默认响应里有矩阵 | 默认没有;`include_internal=True` 才有 | BUG-1325 |
| 同文件回执读取 | `candidate_decision_receipt` | `decision_receipt` | BUG-1325 |
| 两份研究脚本的 `FREEZE` / `REPORT` | `ephemeris_nutation_2026_10_08` | `scoring_perf_2026_10_13` | BUG-1323~1325 改了冻结身份文件,输出不变,ERR-110 另存新记录 |
| 密封合同当前指针 | nutation 记录 | `scoring_perf_2026_10_13`;nutation 放进该对象里的 `previous_*` | 同上 |
| `tests/test_sealed_holdout_contract_freshness.py` 排除前缀 | 到 nutation | 再排除两份新记录 | 同上 |
| `frontend/tests/rectification-confirmation-gate.test.ts` 冻结路径 | nutation 报告 | `sealed_holdout_rerun_scoring_perf_2026_10_13.json` | 同上 |
| `tests/test_repo_privacy_markers.py` 时钟集合行号 | 1182、1190 | 1195、1203 | BUG-1325 的三栏注释把原集合下移,钟点没变 |
## 冻结核对
标签 `scoring_perf_2026_10_13`。nutation 四份文件没有改。
密封重跑:trials 规范化 JSON 与 `sealed_holdout_rerun_ephemeris_nutation_2026_10_08.json` 逐字节相同,metrics 相同,`historical_comparison` 相同,`changed_trial_count` 仍是 8。新报告 sha256 `25e2e59ecab81b528f0f27369a8638a907ea551f57fdd8572db00fe25a139641`。冻结记录 sha256 `1ce7f7ac67221e10bb4d176f5e8af9299fbae7586717d83048b7e3c124e43e7c`。当前树遗留 12 文件哈希 `1c146bf5273edf871d885e9e2e68ee1c8a2f71759b54b4b878f63e771f44197c`(`active_rectification_event_engine.py` 在这 12 个文件里,所以这份哈希变了,输出没变)。
报偏移 900 例:trials 规范化 JSON、summary、`historical_comparison` 都与 `reported_offset_ephemeris_nutation_2026_10_08.json` 相同。`changed_trial_count` 仍是 581。这份报告没有 `metrics` 键,旧报告也没有。新报告 sha256 `9466cf3945a63621104157fb34291cb23205ddb045effa7e70f3c35647516443`。冻结记录 sha256 `1560f24ffea19116c904272907ff9cce24904960406676f3aada3c8c174cf98a`。重跑从 `2026-10-13T17:45:36Z` 到 `2026-10-13T18:02:16Z`。
## 本单不做
- 探针路径的大运用的是请求日期,并且不接收那罗延子运表。
- 候选特征快照瘦身要动前端契约。
- 引导窗口和换段邻近共用同一张大运起点表。
## 自测
- `tests/test_rect_scoring_perf_20261013.py` 与任务书点名的校正测试、`tests/test_rectification_*.py`(当时尚未改指针的完整性门除外)退出码 0。
- 指针改完后 `tests/test_sealed_holdout_contract_freshness.py` 退出码 0。
- 前端 `tsc --noEmit` 退出码 0,`npm run lint` 0 error。`rectification-v9-engine-contract.test.ts` 18 通过、0 失败、0 取消。`rectification-confirmation-gate.test.ts` 8 通过、0 失败、0 取消。
- 没有跑前端全量,也没有跑 Python 快速门。
@@ -38,3 +38,7 @@
- `JYOTISH_REPORT_RENDER_FAST` 默认关。字节一致,内存还降了约 12%,但端到端没到 35%。
- `JYOTISH_REPORT_REFERENCE_CACHE` 默认开。命中与未命中字节一致,命中中位约 0.06 秒。版本号缺失或是 `unknown` 时不缓存。
## 第 1 次打回
合并最新 `origin/staging` 后,把 `report_reference_cache` 登记进 `OFFLINE_SCRATCH_NAMES`。清理逻辑没改:这个目录仍由 `consult_full_data_cache.get_or_build` 在每次调用时删掉两天前的文件。没有改两个缓存模块的行为。
+8 -4
View File
@@ -467,12 +467,16 @@
| 任务书 | 进度 | 主题 | 状态 | 落点 |
| --- | --- | --- | --- | --- |
| `TASK-rect-scoring-perf-20261013.md` | — | 校正打分提速:引导窗口平方扫描、候选不变量重复算、响应带无读取点字段、候选数上限 241(BUG-1323~1325、1345) | 待领取 | `codex/rect-scoring-perf-20261013` |
| `TASK-node-runtime-resources-20261013.md` | — | 报告 worker abort 监听泄漏、本地 PG 适配层往返与元数据缓存、无上限内存表、用户端会话读缓存(BUG-1326~1328、1346,PG 与缓存部分 A/B) | 待领取 | `codex/node-runtime-resources-20261013` |
| `TASK-home-sidebar-rerender-20261013.md` | — | 流式回答时侧栏每帧整栏重渲染(BUG-1329,A/B) | 待领取 | `codex/home-sidebar-rerender-20261013` |
| `TASK-api-disk-cache-retention-20261013.md` | — | API 磁盘缓存只进不出、VedAstro 审计文件留存出生资料、失败快照久缓存、缓存键规范化(BUG-1330~1332,A/B) | 待领取 | `codex/api-disk-cache-retention-20261013` |
| `TASK-rect-scoring-perf-20261013.md` | `PROGRESS-rect-scoring-perf-20261013.md` | 校正打分提速:引导窗口平方扫描、候选不变量重复算、响应带无读取点字段、候选数上限 241(BUG-1323~1325、1345) | 待验收 | `codex/rect-scoring-perf-20261013` |
| `TASK-node-runtime-resources-20261013.md` | `PROGRESS-node-runtime-resources-20261013.md` | 报告 worker abort 监听泄漏、本地 PG 适配层往返与元数据缓存、无上限内存表、用户端会话读缓存(BUG-1326~1328、1346,PG 与缓存部分 A/B) | 待验收 | `codex/node-runtime-resources-20261013` |
| `TASK-node-runtime-resources-fix-20261014.md` | `PROGRESS-node-runtime-resources-20261013.md` | **#58 第 1 次打回**:`4c3485bc` 其余全过;压测脚本放在 `frontend/scripts/` 却从 `frontend/tests/` 导入,镜像构建会失败(BUG-1140 形状,任务书指定的路径有误)。挪到 `frontend/tests/` 下非 `.test` 文件名 | 待验收 | `codex/node-runtime-resources-20261013` |
| `TASK-home-sidebar-rerender-20261013.md` | `PROGRESS-home-sidebar-rerender-20261013.md` | 流式回答时侧栏每帧整栏重渲染(BUG-1329,A/B) | 待验收 | `codex/home-sidebar-rerender-20261013` |
| `TASK-home-sidebar-rerender-fix-20261014.md` | `PROGRESS-home-sidebar-rerender-20261013.md` | **#59 第 1 次打回**:`63509431` 其余全过;`chat-navigation-a11y-contract` 按源码文本断言 `onOpenBilling` 旧写法未跟改(§7.8) | 待验收 | `codex/home-sidebar-rerender-20261013` |
| `TASK-api-disk-cache-retention-20261013.md` | `PROGRESS-api-disk-cache-retention-20261013.md` | API 磁盘缓存只进不出、VedAstro 审计文件留存出生资料、失败快照久缓存、缓存键规范化(BUG-1330~1332,A/B) | 待验收 | `codex/api-disk-cache-retention-20261013` |
| `TASK-report-reference-perf-20261013.md` | `PROGRESS-report-reference-perf-20261013.md` | 长报告出稿提速:术语替换命中预检、哈希单次遍历、同盘复用(BUG-1335~1336,A/B) | 待验收 | `codex/report-reference-perf-20261013` |
| `TASK-report-reference-perf-fix-20261014.md` | `PROGRESS-report-reference-perf-20261013.md` | **#61 第 1 次打回**:`69c739fb` 本单全过;与清理规则合并后,长报告缓存目录补进自行清理名单 | 待验收 | `codex/report-reference-perf-20261013` |
| `TASK-consult-prep-parallel-20261013.md` | — | 普通对话发问前准备步骤并行、模型版本短缓存、多领域并发开关(BUG-1337~1339,A/B) | 待领取 | `codex/consult-prep-parallel-20261013` |
| `TASK-consult-prep-parallel-fix-20261014.md` | — | **#62 第 1 次打回**:`a0e223e2` 业务逻辑通过;两条源码文本断言未跟改(§7.8)、A/B 脚本从 `frontend/tests` 导入(BUG-1140) | 待领取 | `codex/consult-prep-parallel-20261013` |
| `TASK-frontend-dead-code-20261013.md` | — | 前端死代码 17 文件与无调用方接口删除,含未登录重计算接口(BUG-1342) | 待领取 | `codex/frontend-dead-code-20261013` |
| `TASK-api-chart-subprocess-gate-20261013.md` | — | 合盘不带 skip 串行排盘、报告无效子进程、名额轻重混用(只模拟)(BUG-1333~1334,A/B) | 待领取(排队:api-disk-cache-retention + report-reference-perf) | `codex/api-chart-subprocess-gate-20261013` |
| `TASK-answer-effort-ab-20261013.md` | — | 答题步推理强度开关 + A/B(需模型 key) | 待领取(排队:consult-prep-parallel) | `codex/answer-effort-ab-20261013` |
@@ -0,0 +1,41 @@
# TASK · 发问准备并行修复单(issue #62,第 1 次打回)
- 日期:2026-10-14
- 原任务书:`docs/tasks/TASK-consult-prep-parallel-20261013.md`
- 被验 SHA:`a0e223e20cebcce3479accb60f6aec44d1caadda`(`codex/consult-prep-parallel-20261013`)
- 执行方:Grok,同一分支续做(先 merge 最新 `origin/staging`,不改写已推历史)
- BUG 编号:沿用 BUG-1337~1339
## 1. 验收结论:业务逻辑通过;前端全量多出 3 条真失败
| 检查 | 结果 | 证据 |
| --- | --- | --- |
| 开关全关时的顺序 | 通过 | `turn-prep.ts` 串行分支与原 `route.ts` 的 401→423→400→503→404→409→409→503 逐条同序 |
| 开关开时 | 通过 | 删号判定仍最先返回、在任何写库扣点之前;审核结论在 `beforeReserve` 内等齐,被拦不 reserve |
| `readVersion` 缓存 | 通过 | 只缓存成功结果,`invalidateLanguageModelCatalog` 同时清;默认 TTL 0 |
| tsc / lint | 通过 | 0 错 / 0 error |
| 前端全量 `npm test`(与 staging 逐名比对) | **未通过:新增 3 条** | 见下 |
1. `frontend/tests/chat-session-authority.test.ts`「consult POST on a rectification session is 409, a missing id is 404」:第 65 行在 `route.ts` 源码里找 `/if \(!chatSession\) \{[\s\S]*status: 404/`——这段判定挪进了 `frontend/src/lib/consult/turn-prep.ts`(`sessionMissing()`),断言没跟着挪。
2. `frontend/tests/consultation-workflow-contract.test.ts`「consultation plans are server-owned and bounded」:第 160 行找 `/beforeReserve: \(\{ consultationMode \}\) => createConsultationPlan\(\{/`,第 161 行找 `reserve: () => reserveConsultationModel(`——两处都改成了 `async` 函数体。
3. `frontend/tests/runtime-sources-no-test-imports.test.ts`:`frontend/scripts/research/consult-prep-parallel-ab.mts` 第 9 行从 `../../tests/support/stub-server-only.mjs` 导入。web 镜像不复制 `frontend/tests`,推上 staging 后镜像构建会失败(BUG-1140;#58 刚因同一形状打回过一次)。
原任务书 §5 第 7 条已经列出要先 grep 的源码文本断言;这次漏的两条不在那份清单里,但属于同一类(AGENTS.md §7.8)。
## 2. 修法要求
1. **1、2 两条**:按 §7.3 写「原值 / 新值 / 原因」三栏改断言,**意图不得放宽**:
- 1:改为在 `turn-prep.ts` 里锁「查不到会话 → 404」「类型不是 consultation → 409 `session_not_consultation`」,并保留第 70 行那条「不得合并成一个判断」的反向断言(针对新文件)。
- 2:改为锁「`beforeReserve` 里调用 `createConsultationPlan`」「`beforeReserve` 在 `reserve` 之前」「`reserve` 调用 `reserveConsultationModel`」,允许 `async` 写法,但不得只查函数名存在。
2. **第 3 条**:把 `consult-prep-parallel-ab.mts` 挪到 `frontend/tests/` 下(文件名不得以 `.test.ts` / `.test.tsx` 结尾),导入改相对路径;同步改 PROGRESS 与 `docs/testing/consult-prep-parallel-ab-20261013.md` 里的命令路径。`frontend/scripts/research/` 下其它新增文件同样检查。
3. 再 grep 一遍 `route.ts` 被挪走 / 改写的语句在 `frontend/tests`、`tests` 里还有没有按源码文本断言的:`grep -rn "chatSession\.session_type\|getUser()\|refuseWhenAccountDeletionPending\|resolveSessionLanguageModel(\|reserveConsultationModel(\|createConsultationPlan(" frontend/tests tests`,命中的逐条确认。
4. 业务代码不改;三个开关默认值不变。
## 3. 验收标准
- 前端全量 `npm test` 失败清单与 staging 基线逐名相同(本机另有 Docker 类失败,以基线为准);
- `git diff a0e223e2..<新 SHA> -- frontend/src` 为空。
## 4. 让步顺序
无。第 1 次打回。
@@ -0,0 +1,36 @@
# TASK · 侧栏重渲染修复单(issue #59,第 1 次打回)
- 日期:2026-10-14
- 原任务书:`docs/tasks/TASK-home-sidebar-rerender-20261013.md`
- 被验 SHA:`63509431529d212c7847371e7717660d823b40e6`(`codex/home-sidebar-rerender-20261013`)
- 执行方:Grok,同一分支续做(落后 staging 时用 merge,不改写已推历史)
- BUG 编号:沿用 BUG-1329
## 1. 验收结论:一项未通过,其余全部通过
| 检查 | 结果 | 证据 |
| --- | --- | --- |
| 前端全量 `npm test`(与 staging 基线逐名比对) | **未通过:新增 1 条失败** | `frontend/tests/chat-navigation-a11y-contract.test.ts`「in-app destinations navigate client-side so the chat survives the round trip」:`The input did not match the regular expression /onOpenBilling: \(\) => openAccountDialog\("billing", \{ source: "account-menu" \}\)/` |
| T1 稳定包装 + 比较后发布 | 通过 | 逐行看过:`latestRef` 在无依赖 effect 里写,发布 effect 在其后;未冻结首次闭包;`HomeProbe` 的故意不稳定输入未改 |
| T2 `visibleSessions` 记忆化 | 通过 | — |
| T3 `SidebarProvider` context 记忆化 | 通过 | — |
| 改既有断言 | 通过 | `session-list-lifecycle` 三栏齐全,且加强了(再改一版后仍调到最新) |
| tsc / lint | 通过 | 0 错 / 0 error |
**根因**:`use-home-shell-registration.ts` 把 `onOpenBilling` 从 `() => openAccountDialog("billing", { source: "account-menu" })` 改成了 `() => { latestRef.current?.openAccountDialog("billing", { source: "account-menu" }); }`,而 `chat-navigation-a11y-contract.test.ts` 第 42 行按源码文本断言旧写法(AGENTS.md §7.8:改写语句前要 grep 按源码文本断言的合同测试,同一轮跟着改)。
## 2. 修法要求
1. 只改 `frontend/tests/chat-navigation-a11y-contract.test.ts` 第 42 行这条断言,按 §7.3 写「原值 / 新值 / 原因」三栏。新正则要**仍然锁住意图**:账户菜单里的「充值」打开 billing 且 `source: "account-menu"`。例如匹配 `onOpenBilling: \(\) => \{ latestRef\.current\?\.openAccountDialog\("billing", \{ source: "account-menu" \}\); \}`;不得放宽成只查 `"billing"`。
2. 再 grep 一遍:`grep -rn "onOpenProfile\|onOpenGeneral\|onOpenLogout\|onNewChat\|onSelectSession\|onLoadMore" frontend/tests`,有按旧写法断言源码文本的同样处理(本次全量里只红了这一条,但要确认)。
3. 业务代码不改。先把最新 `origin/staging` 合并进分支(用 merge)。
4. PROGRESS 末尾记一行。
## 3. 验收标准
- 前端全量 `npm test` 失败清单与 staging 基线逐名相同;
- `git diff 63509431..<新 SHA> -- frontend/src` 为空。
## 4. 让步顺序
无。第 1 次打回;再打回会停下等产品负责人。
@@ -0,0 +1,39 @@
# TASK · 服务器内存与数据库往返修复单(issue #58,第 1 次打回)
- 日期:2026-10-14
- 原任务书:`docs/tasks/TASK-node-runtime-resources-20261013.md`
- 被验 SHA:`4c3485bc2352e8f9de097d81d9979092ee2bb280`(`codex/node-runtime-resources-20261013`)
- 执行方:Grok,同一分支续做(落后 staging 时用 merge,不改写已推历史)
- BUG 编号:沿用 BUG-1326~1328、1346
## 1. 验收结论:一项未通过,其余全部通过
| 检查 | 结果 | 证据 |
| --- | --- | --- |
| 前端全量 `npm test`(与 staging 基线逐名比对) | **未通过:新增 1 条真实失败** | `runtime-sources-no-test-imports.test.ts`「files copied into the web image never import from frontend/tests」:`actual: ['scripts/bench-local-pg-roundtrips.ts']` |
| 同上,另一条新增 | 环境缺口(不算未通过) | `database-local-postgres-session-setup.test.ts` 报 `spawnSync docker ENOENT`,本机无 Docker;以 Grok 的 test:db 回报为准 |
| T1 报告 worker 摘监听 / T1b | 通过 | 代码与新测试逐行看过 |
| T2 元数据缓存 + 合并身份设置 | 通过 | 角色仍只来自构造函数白名单;只缓存表结构;`off` 走原语句顺序;A/B 记录 49→32 往返、中位数降 51.9%、逐字节一致 |
| T3 三张内存表 | 通过 | — |
| T6 登录读缓存 | 通过(默认关,理由成立) | 改密码 / 注销 / 后台三处已强制绕过;默认关是因为没有身份库真实耗时对照,符合原任务书门槛 |
| tsc / lint / next build | 通过 | 0 错 / 0 error / `/` 仍 Static |
| 越界 / 隐私 | 通过 | — |
**根因**:`frontend/scripts/bench-local-pg-roundtrips.ts` 第 16 行 `import { startPostgresFixture } from "../tests/helpers/postgres-fixture.ts";`。web 镜像只复制 `frontend/src` 与 `frontend/scripts`,不复制 `frontend/tests`,而 `next build` 会类型检查 `frontend/` 下所有 `.ts`——推上 staging 后镜像构建会失败(BUG-1140,同一形状)。**这条路径是原任务书 T4 指定的,错在任务书,不是执行偏差。**
## 2. 修法要求
1. 把脚本挪到 `frontend/tests/bench-local-pg-roundtrips.ts`(文件名**不得**以 `.test.ts` 结尾,避免被 `npm test` 自动收进去),导入改成 `./helpers/postgres-fixture.ts`;脚本头注释里的运行命令改成 `npx tsx tests/bench-local-pg-roundtrips.ts`。
2. 同步改引用:`docs/tasks/PROGRESS-node-runtime-resources-20261013.md`、`docs/testing/node-runtime-resources-ab-20261013.md`。原任务书不改(历史记录),在 PROGRESS 里写一行「按修复单挪位置」。
3. 不改任何业务代码;A/B 数字不用重跑。
4. 先把最新 `origin/staging` 合并进分支(用 merge)。
## 3. 验收标准
- `frontend/tests/runtime-sources-no-test-imports.test.ts` 通过;
- 前端全量 `npm test` 的失败清单只剩 staging 基线那 24 条 + 本单新增的 Docker 测试(无 Docker 时);
- `git diff 4c3485bc2..<新 SHA> -- frontend/src` 为空(业务代码一字未动)。
## 4. 让步顺序
无。这是第 1 次打回;再打回会停下等产品负责人。
@@ -0,0 +1,36 @@
# TASK · 长报告提速修复单(issue #61,第 1 次打回)
- 日期:2026-10-14
- 原任务书:`docs/tasks/TASK-report-reference-perf-20261013.md`
- 被验 SHA:`69c739fbee3f5af6deed911482d82e49ed429bf7`(`codex/report-reference-perf-20261013`)
- 执行方:Grok,同一分支续做(先 merge 最新 `origin/staging`,不改写已推历史)
- BUG 编号:沿用 BUG-1335、1336
## 1. 验收结论:本单自身全部通过;与 #60 合并后一条合同测试红
| 检查 | 结果 | 证据 |
| --- | --- | --- |
| 与最新 staging 合并后的定向测试 | **未通过** | `tests/test_api_scratch_retention.py::test_new_scratch_local_dirs_are_registered_or_whitelisted`:`AssertionError: ['report_reference_cache']` |
| 逐字节一致(Claude 在 Linux、屏蔽 PyJHora 复跑 A/B) | 通过 | 四张虚构盘 A / B 未命中 / B 命中 / 缓存首算的五个字段 sha 全部相同;`format=json`、`edition=reference` 两条 sha 相同 |
| 耗时 | 与回报一致 | 未命中中位数 21.1→15.6 s(day)等,降约 22–26%,未到 35% 门槛 → 渲染提速默认关正确;命中 0.02–0.03 s |
| 缓存键含 `today` | 通过 | `_high_rigor_birth_payload` 在缺省时把当天日期写进 `birth`,跨天不会命中 |
| `GITHUB_SHA` | 通过 | 部署编排已传入;缺失或 `unknown` 时不缓存 |
| `jyotish_api_server.py` | 通过 | 零改动 |
**根因**:#60(BUG-1330~1332,已在 staging)新增了合同测试:`scripts/` 里写 `scratch/local/<子目录>` 的地方,必须登记在 `scripts/api_scratch_retention.py` 的 `REGISTRY`(服务器周期清理)或 `OFFLINE_SCRATCH_NAMES`(自己会清理的缓存)里。本单新增的 `scratch/local/report_reference_cache/` 两边都没登记。两单各自都对,合在一起才红——这不是你的疏漏,是两单同时在做。
## 2. 修法要求
1. 合并最新 `origin/staging`(含 #60)。
2. 在 `scripts/api_scratch_retention.py::OFFLINE_SCRATCH_NAMES` 加 `"report_reference_cache"`,旁边写一行注释:它与 `consult_full_data_cache` 同走 `consult_full_data_cache.get_or_build`,每次调用先 `prune_cache(name=…)` 删两天前的文件,自己会清;含出生资料,保留期 2 天。
3. 不改两个模块的任何逻辑。
4. PROGRESS 末尾记一行。
## 3. 验收标准
- `python -m pytest tests/test_api_scratch_retention.py tests/test_report_reference_perf.py tests/test_consult_card_full_source.py -q` 全绿;
- Claude 全量 pytest 与 staging 基线逐条比对无新增。
## 4. 让步顺序
无。第 1 次打回。