merge origin/staging into api disk cache retention (issue #60)
Independent Staging Quality Gate / validate (push) Successful in 13m18s
Independent Staging Quality Gate / publish (push) Successful in 3m37s

Docs-only conflicts resolved by keeping both; agent-loop rule A.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LutgzyJqNhPpZy1nFsJtN3
This commit is contained in:
Claude
2026-10-14 09:11:01 +08:00
64 changed files with 48295 additions and 172 deletions
@@ -0,0 +1,12 @@
# 真机走查 · 回答生成时侧栏不再跟着闪(BUG-1329,issue #59)
浏览器 A/B 未跑。部署到 staging 后,在 `https://staging.jyotisha.chat` 登录一个没有真实会话内容需要露出的账号,按顺序看:
1. 电脑浏览器打开首页。左侧会话列表的样子、顺序、分组和以前一样。
2. 发一个普通问题,等回答一个字一个字出来。这段时间左侧列表不跟着闪、不跟着整栏重画。回答本身仍是逐字出现。
3. 回答过程中点另一条会话,能打开那一条。点当前这条的菜单,改名、置顶、分享、删除仍可用,改的是刚刚点的那一条。
4. 右上角账户菜单仍能打开资料、通用、账单和退出。
5. 换一个人物后,左侧列表换成那个人的会话,不串到别人的。
6. 手机宽度再看一遍第 2 步。侧栏抽屉的开关和以前一样。
任何一步不对,在 issue #59 里写是哪一步、哪台设备,并把标签改回 `agent/待规划`。不要贴出真实会话内容。
@@ -0,0 +1,18 @@
# A/B · 回答生成时侧栏重画(BUG-1329,issue #59)
同一测试 `frontend/tests/home-sidebar-rerender.test.tsx`,同一输入。A 是改代码前的 `66cd60081f37a57680274633fcb3fb942d01bb2f`(任务书写的 `77057a819` 已被后续提交盖过)。B 是分支 `codex/home-sidebar-rerender-20261013`。各跑 3 次。会话都是虚构的「Synthetic session N」。没有真实会话内容。
度量是 60 帧里的注册次数、侧栏提交次数、这 60 帧的 Profiler 耗时合计。内容用剔除函数字段后的 SHA-256 比较。
| 档 | A 注册 / 提交 / 耗时中位 | B 注册 / 提交 / 耗时中位 | 内容 |
| --- | --- | --- | --- |
| 30 条 | 60 / 60 / 2778.961 毫秒 | 0 / 0 / 0 | 两边都是 `b18f05a3d83be5b41584787b7c0495f1fcec8ef7b8ecfbdbb3c083c40796c103` |
| 100 条 | 60 / 60 / 11799.253 毫秒 | 0 / 0 / 0 | 两边都是 `cef0a63d6f3fe72e541f9ac882b8eaf305b6933fdd07ca3002e8cd03bb139d25` |
A 的三次 30 条耗时:2774.964、2778.961、4202.085。100 条:10530.828、11799.253、12284.103。B 的三次都是 0。
正确性:换当前项后 B 注册 1 次,外壳看到新的当前项。改一行标题后标题更新。换成另一人的会话后列表换掉。只改回调版本不再注册,点「打开会话」和「改名」记到的都是第 4 版。A 在只改回调版本时还会再注册 1 次;B 不注册,但调用结果相同。
判定:B 在 60 帧内注册 0、侧栏提交 0,内容摘要一致,`session-list-lifecycle` 全绿。可以交付。
浏览器 A/B 未跑。
@@ -0,0 +1,13 @@
# 真机清单 · 登录缓存与长时间运行(2026-10-13)
对应 BUG-1326、BUG-1346。在 staging 上用两个浏览器(或一台电脑、一台手机)登录同一个测试账号。不要把账号、口令或页面原文记进仓库。
本轮代码里,登录读缓存默认关闭。要做下面第 2–4 步,服务器环境变量 `IDENTITY_SESSION_COOKIE_CACHE` 必须是 `on`。未设置或其它值时,改密码后另一台设备会马上要求重新登录,第 2 步不会出现「还能浏览大约 5 分钟」。
| 步 | 怎么做 | 通过标准 |
| --- | --- | --- |
| 1 | 两台设备都登录,各自打开首页并翻一两页 | 都能正常看到自己的会话,不要求反复登录 |
| 2 | 设备 A 修改密码。5 分钟内用设备 B 只浏览首页、会话列表和星盘,不要改密码、不要注销 | 设备 B 在这 5 分钟里仍能浏览 |
| 3 | 仍在这 5 分钟内,用设备 B 尝试修改密码或申请注销账户 | 被拒绝,不能拿旧登录做这两件事 |
| 4 | 等到改密码已超过 5 分钟,再用设备 B 刷新 | 被要求重新登录 |
| 5 | 用新密码在设备 B 重新登录,再浏览一次 | 能进入,会话列表还在 |
@@ -0,0 +1,21 @@
# 本地数据库往返对照(2026-10-14)
环境:Windows,Docker 29.8.0,Node v22.23.2。脚本 `frontend/tests/bench-local-pg-roundtrips.ts`(2026-10-14 按修复单从 `frontend/scripts/` 挪来,数字未重跑)。库是测试用的临时 Postgres,数据是虚构用户。每组 50 遍,重复 3 组,先各热身 1 遍。往返数是每组平均值的中位数。耗时中位数是三组中位数的中位数。p95 是全部 150 遍的单遍耗时。
判定用第二次运行(输出里带三组原始数)。第一次运行同样是 49 降到 32,中位数 89.51 毫秒降到 32.70 毫秒,内容一致,方向相同。
| 模式 | 开关 | 往返 | 中位数(毫秒) | p95(毫秒) | 三组(往返 / 中位数毫秒) |
| --- | --- | --- | --- | --- | --- |
| A | 两个都关 | 49 | 75.84 | 88.25 | 49 / 82.51;49 / 75.84;49 / 73.81 |
| B | 两个都开 | 32 | 36.48 | 39.47 | 32 / 36.66;32 / 36.48;32 / 35.71 |
| B1 | 只开元数据缓存 | 40 | 40.54 | 44.37 | 40 / 41.56;40 / 40.54;40 / 39.86 |
| B2 | 只开合并身份设置 | 41 | 67.83 | 72.75 | 41 / 68.46;41 / 66.47;41 / 67.83 |
- 往返:32 ≤ 49 的 70%(34.3)。通过。
- 耗时:下降 (75.84 − 36.48) / 75.84 = 51.9%,不低于 15%。通过。
- 四种模式的业务返回逐字节一致(`payloadMismatch` 为 false)。通过。
- 只开其中一个时,往返都还高于 70% 那一刀;只合并身份设置时,这一次耗时只降了约 10.6%。两个一起才过门槛,所以两个都默认打开。写成 `off` 仍走改前的语句顺序。
登录读缓存没有放进这次真库计时。内存里的登录测试看到普通读取的查库次数从 3 降到 1,但那不是身份库的耗时对照,所以 `IDENTITY_SESSION_COOKIE_CACHE` 保持默认关闭。
`npm run test:db` 两轮都是 81 项、通过 68、失败 13、取消 0。失败名称与 `tools/agent-loop/windows-known-failures.txt` 的 13 条逐条相同,没有多出来的。因此两个数据库开关默认打开。