文件
hyb-oa/.trellis/tasks/08-10-session-fallback-failure-classification/research/execution-evidence.md
T

75 行
6.5 KiB
Markdown
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# 执行证据:生产构建 runner 会话回落
## 环境与原样基线
- 候选:`5518e974a2e85f0036b8f7bbf71f86de0370b6cb`;Node `v22.22.2`;Playwright `1.58.2`。
- runner:`http://127.0.0.1:3000`,单 worker、零 retry。本地 Vite dev 两份目标 spec 为 `15 passed`,历史 8 个标题重复 3 次为 `24 passed`;该结果不等价于历史 `SERVE_CLIENT_DIST=true` 的生产构建 runner。
- 对当前 `dist` 使用 Vite preview 复现生产构建/PWA 行为,两份目标 spec 为 `11 passed / 4 failed`。其中 3 条是历史会话回落标题,另 1 条是资产长表单 toast 遮挡点击,属于本任务外的新失败,不计入 8 条会话分类。
## 历史 8 条逐项映射(原样生产构建 runner)
| 历史标题 | 当前结果 | 说明 |
| --- | --- | --- |
| 七个主要业务台账标题区保持一主操作加至多一个更多,列表工具不常驻 | FAIL | 后续完整导航时停在“正在加载会话...” |
| 采购页使用安全格式上传并通过认证 Blob 下载 | PASS | 本轮未复现历史回落 |
| 采购与资产列表、详情各自只请求职责内数据并恢复 URL 筛选 | PASS | 本轮未复现历史回落 |
| 采购与资产长表单详情对 403/404 使用同一安全错误态 | PASS | 本轮未复现历史回落 |
| 采购长表单切回记录列表时支持取消保持与确认放弃 | PASS | 本轮未复现历史回落 |
| 共享未保存保护覆盖浏览器返回取消、确认与刷新拦截 | FAIL | 接受 reload 后停在“正在加载会话...” |
| /projects /assets /reimbursements 在中等宽度下操作列可达且页面不横溢 | FAIL | 后续完整导航时停在“正在加载会话...” |
| E2E 全局搜索:采购与资产忽略旧 href 并使用实体 canonical 路径 | PASS | 第二次回到 portal 的历史回落本轮未复现 |
## 聚焦 trace 安全账本
聚焦复跑“七个主要业务台账标题区”仍失败。原始 trace 只保留在 gitignored 测试输出中;下列账本仅从中提取白名单字段:
- browser origin:loopback `http://127.0.0.1:3000`;context `serviceWorkers=allow`。
- 导航序列:`/login` → `/purchase-requests` → `/contracts-registry` → `/projects` → `/assets` → `/payment-batches`。
- login:`POST /api/auth/login -> 200`;随后 `GET /api/me -> 200`。
- 前四次完整业务导航均发出 `POST /api/auth/refresh -> 200`,并各自完成 `GET /api/me -> 200`。
- 最后一次完整导航仍发出 `POST /api/auth/refresh -> 200`,但其后的 `GET /api/me` 未完成;页面保持“正在加载会话...”,业务标题断言超时。
- 因每次完整导航都触发 refresh,`has_session` 缺失假设被本 witness 反证;当前控制变量应转向生产构建才启用的 PWA Service Worker,而不是重复安装 session hint。
## 下一控制变量
两份目标 spec 当前允许 Service Worker,而仓库现有认证、权限、合同和关键流程 E2E 普遍显式使用 `serviceWorkers: "block"`。下一步仅在 test context 增加该设置,保持 mock、业务断言、导航次数和产品认证代码不变;若同一生产构建 runner 消除历史回落,再结合独立前端 bootstrap 与后端 rotation 对照完成分类。
## 单变量控制结果
- 仅为两份目标 spec 增加 `test.use({ serviceWorkers: "block" })`;未改 mock 响应、业务断言、完整导航、retry、PWA 产品实现或认证产品代码。
- 同一 production-built preview、单 worker、零 retry 下,历史 8 个标题由原样基线的 3 FAIL / 5 PASS 变为 `8 passed`。
- 该设置与这些 spec 的测试边界一致:用例以 `page.route` 合成认证和业务 API;PWA Service Worker 属于被测页面之外的网络代理,会让 mock 拦截在构建产物下随安装/接管时机变化。阻断它不是弱化会话语义,而是让 API mock 成为该测试唯一网络事实源。
## 独立认证对照
- 真实前端 bootstrap:`login-portal-ux.spec.ts` 的“Portal bootstrap refresh 首次瞬时失败后重试成功仍保留登录态”在同一 preview runner 下 `1 passed`。该用例显式安装 session hint,第一次 refresh 返回瞬时 500、后续重试成功,最终保持 `/portal`。
- 后端 focused route:`auth.login.test.js` 为 `30 passed`,包含登录建立 session、refresh 前锁定并重查账号、密码变更/重置撤销 session 等合同。
- 真实本地 PostgreSQL/HTTP:`run-web-gates.sh auth-security-local` 的 target gate 强制 loopback API、loopback PostgreSQL 与 `hyb_oa_auth_*` 临时库;实际自动避开已占用端口,应用 65 条迁移、写入合成种子并完成 `9/9` 认证安全回归,含 refresh/reset race,最终 `AUTH-REGRESSION PASS FULL`。cleanup 后同前缀临时数据库计数为 0。
- 全过程未连接生产、未使用生产凭据、未部署。
## 分类检查点(先于永久修法)
**唯一分类:FIXTURE。**
支持证据:
1. 原样 production-built/PWA runner 可重复复现同类会话 bootstrap 卡住;Vite dev 不复现,说明 runner 差异是必要条件。
2. trace 反证 session hint 缺失:失败前每次完整导航都发出 refresh;最后一次 refresh 仍为 200,卡点是其后 `/api/me` 未完成。
3. 单一 test-context 变量 `serviceWorkers: "block"` 在保持 8 条业务断言与完整导航不变时消除全部历史回落。
4. 真实前端 bootstrap、后端 route 合同和 loopback 真实 PostgreSQL/HTTP 认证回归均通过,未出现同一会话回落根因。
反证与边界:
- 本轮没有证据支持 PRODUCT:认证产品代码未修改,真实后端 refresh/reset 竞争通过。
- 本轮没有证据支持 MIXED:fixture 控制消除历史 8 条失败,独立产品对照均通过。
- 资产长表单 toast 遮挡是本轮新观察的非会话失败,不改变本分类,也不在本任务顺手修复。
基于该检查点,允许把两处 `serviceWorkers: "block"` 保留为最小 test-only 修复;不得删除断言、完整导航或增加 retry。
## 修法后的完整目标回归
- 同一 production-built preview、单 worker、零 retry 完整运行两份目标 spec:`15 passed / 0 failed / 0 skipped`。
- 历史 8 条全部包含在该结果中;两份文件测试总数仍为 15,关键完整导航未减少。
- 原样基线出现过的资产长表单 toast 遮挡在完整复跑中通过,按一次性非会话观察保留在基线说明中,不新登记本任务 residual。
- 聚焦诊断 raw trace 已从本地 HTML report 数据目录删除;任务只保留本文件中的白名单账本。