修复在线游玩加载体验:加载期黑屏/空白与发行资源传输开销(#636) #639

Merged
suzmii merged 3 commits from fix/game-play-loading into master 2026-10-05 19:13:45 +08:00
Member

关联 Issue:#636

现象与实测对照

用户反馈「进入游玩…加载有点慢,一直黑屏体验不好」。用真实栈(真实 SpacetimeDB + 真实私有 OSS + 真实发行包 + 真实 Chromium)复现,链路按 4 Mbps / 100 ms 模拟(按真实线字节数延迟后投递)。夹具是真实 AGC 发行包形状:根 index.html + 真实 Phaser 4 压缩包 assets/phaser.min.js(1,375,976 B)+ 脚本 + 素材。

观测点 改前 改后
用户端「开始游戏」→ 游戏画面可见 3298 ms 1543 ms
用户端加载期界面 99.3% 像素亮度 < 24 的近黑面板 + 一行 游戏正在启动… 共享加载面:封面 + 标题 + 动效进度 + 阶段文案
后台「试玩当前待审版本」→ 游戏画面可见 4587 ms 2694 ms
后台试玩加载期界面 iframe 直接 opacity:1,区域全白空白,页面全程无加载文案 同一加载面(浅色面板语气)
assets/phaser.min.js 传输 1,375,976 B(Content-Encoding: none,模拟 2724 ms) 353,336 B(gzip,模拟 774 ms)
发行资源校验器 无 ETag 强 ETag,命中 If-None-Match 返回 304

改动

前端:两端共用同一个加载面

  • 新增 packages/shared/src/components/PlatformGameLoadingSurface.tsx:封面/标题 + 动效进度条 + 按时长推进的阶段文案(准备 → 加载游戏资源 → 启动游戏引擎)+ 慢加载提示;role="status" / aria-busy;样式写进 packages/shared/src/components/styles.css(后台没有 Tailwind,共享组件不能只靠工具类撑外观)。
  • 网页游玩页 GamePlayPage:一行小字换成加载面,加载上限改为共享常量 PLATFORM_GAME_LOADING_TIMEOUT_MS(20 秒,GAME_PLAY_STARTUP_TIMEOUT_MS 仍是同一口径的再导出);onLoad 后淡入画面、超时面板与重试/返回不变。
  • 后台审核页 AdminGameDistributionReviewPage:试玩区包一层加载面,onLoad 后才让位给画面;补 20 秒超时说明与「重新创建试玩会话」入口;新建会话重置加载态,不会沿用上一个会话的 ready。

后端:发行网关的传输与条件请求

  • 文本类发行资源(HTML/JS/CSS/JSON/SVG/WASM,≥1 KiB)在客户端接受 gzip 时下发 Content-Encoding: gzip + Vary: Accept-Encoding;图片/音频/视频等已是压缩格式的资源不压,小文件不压。
  • 下发按 versionId + 资源路径 摘要的强 ETag;命中 If-None-Match 返回 304(无正文,保留 Cache-Control 与 ETag)。max-age=60, must-revalidate 与撤销窗口都不变,差别只是 60 秒之后重复游玩不再重下整包。
  • 后台试玩会话仍是 no-store 且不给 ETag;* 校验器对包内不存在的路径仍返回 404。

文档与门禁

  • docs/project-memory/shared-memory/pitfalls.md、docs/【开发运维】本地开发验证与生产运维-2026-05-15.md、deploy/nginx/README.md 与两份里程碑记录同步现行口径。
  • scripts/check-game-distribution-ops-rollback-e2e.mjs 补四条断言:压缩 + Vary、强 ETag、If-None-Match → 304(无正文)、不接受 gzip 时不压缩。

验证

命令 结果
cargo test -p api-server --bin api-server -- game_distribution 49 passed(含 5 条新增:ETag 作用域、If-None-Match 列表/弱校验/gzip;q=0、文本压缩与二进制/小文件不压、304 无正文与 * 对缺失路径 404)
npx vitest run packages/shared/src/components/PlatformGameLoadingSurface.test.tsx src/components/game-distribution/GameDistributionPages.test.tsx apps/admin-web/src/pages/AdminGameDistributionReviewPage.test.tsx 51 passed
npm run check:game-distribution-ops-rollback-e2e 47 PASS(真实栈 + 真实 OSS,含本轮四条新断言)
npm run typecheck / admin-web typecheck / npm run check:encoding / git diff --check 通过
真实浏览器 smoke 用户端与后台端加载面/画面截图(见下),链路 4 Mbps 模拟

自查(Review 轮次)

本轮 review 发现 7 处问题(2 处会让 CI 变红)并全部修复:Rust 未过 cargo fmt、ESLint 4 处(含共享组件文件同时导出常量触发 react-refresh/only-export-components)、主规范未同步发行缓存契约、nginx README 与 Pingora 口径自相矛盾、后台超时态仍转圈且 aria-busy 为 true、Q=0 大小写、pitfalls 措辞;并按实测把大文件压缩从 level 6 降到 level 1。逐条证据与「复核过无问题」的结论见下方评论。

边界与不做项

  • 不改 publicationRevision、审核 CAS、/games/<gameId>/ 路由、Cookie 拒绝与 sandbox="allow-scripts" 口径。
  • 边缘 gzip/Brotli 与本层不冲突(两边都以「响应已带 Content-Encoding 就跳过」收口);Pingora 网关在自身压缩关闭时会移除 accept-encoding,那种部署形态下源站压缩不生效,属于网关侧口径,本次不改。
  • 一次性实测/截图探针脚本不入库(.tmp/ 为 gitignored)。

截图(真实 Chromium,4 Mbps 模拟链路)

用户端加载面(改后):

用户端加载面

用户端画面就绪:

用户端画面

后台试玩加载面(改前这里是全白空白、没有任何文案):

后台试玩加载面

后台试玩画面就绪:

后台试玩画面

关联 Issue:#636 ## 现象与实测对照 用户反馈「进入游玩…加载有点慢,一直黑屏体验不好」。用真实栈(真实 SpacetimeDB + 真实私有 OSS + 真实发行包 + 真实 Chromium)复现,链路按 4 Mbps / 100 ms 模拟(按真实线字节数延迟后投递)。夹具是真实 AGC 发行包形状:根 `index.html` + 真实 Phaser 4 压缩包 `assets/phaser.min.js`(1,375,976 B)+ 脚本 + 素材。 | 观测点 | 改前 | 改后 | | --- | --- | --- | | 用户端「开始游戏」→ 游戏画面可见 | 3298 ms | **1543 ms** | | 用户端加载期界面 | 99.3% 像素亮度 < 24 的近黑面板 + 一行 `游戏正在启动…` | 共享加载面:封面 + 标题 + 动效进度 + 阶段文案 | | 后台「试玩当前待审版本」→ 游戏画面可见 | 4587 ms | **2694 ms** | | 后台试玩加载期界面 | iframe 直接 `opacity:1`,区域全白空白,**页面全程无加载文案** | 同一加载面(浅色面板语气) | | `assets/phaser.min.js` 传输 | 1,375,976 B(`Content-Encoding: none`,模拟 2724 ms) | **353,336 B(gzip,模拟 774 ms)** | | 发行资源校验器 | 无 ETag | 强 ETag,命中 `If-None-Match` 返回 304 | ## 改动 ### 前端:两端共用同一个加载面 - 新增 `packages/shared/src/components/PlatformGameLoadingSurface.tsx`:封面/标题 + 动效进度条 + 按时长推进的阶段文案(准备 → 加载游戏资源 → 启动游戏引擎)+ 慢加载提示;`role="status"` / `aria-busy`;样式写进 `packages/shared/src/components/styles.css`(**后台没有 Tailwind**,共享组件不能只靠工具类撑外观)。 - 网页游玩页 `GamePlayPage`:一行小字换成加载面,加载上限改为共享常量 `PLATFORM_GAME_LOADING_TIMEOUT_MS`(20 秒,`GAME_PLAY_STARTUP_TIMEOUT_MS` 仍是同一口径的再导出);`onLoad` 后淡入画面、超时面板与重试/返回不变。 - 后台审核页 `AdminGameDistributionReviewPage`:试玩区包一层加载面,`onLoad` 后才让位给画面;补 20 秒超时说明与「重新创建试玩会话」入口;新建会话重置加载态,不会沿用上一个会话的 ready。 ### 后端:发行网关的传输与条件请求 - 文本类发行资源(HTML/JS/CSS/JSON/SVG/WASM,≥1 KiB)在客户端接受 `gzip` 时下发 `Content-Encoding: gzip` + `Vary: Accept-Encoding`;图片/音频/视频等已是压缩格式的资源不压,小文件不压。 - 下发按 `versionId + 资源路径` 摘要的强 `ETag`;命中 `If-None-Match` 返回 304(无正文,保留 `Cache-Control` 与 `ETag`)。`max-age=60, must-revalidate` 与撤销窗口都不变,差别只是 60 秒之后重复游玩不再重下整包。 - 后台试玩会话仍是 `no-store` 且不给 ETag;`*` 校验器对包内不存在的路径仍返回 404。 ### 文档与门禁 - `docs/project-memory/shared-memory/pitfalls.md`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`、`deploy/nginx/README.md` 与两份里程碑记录同步现行口径。 - `scripts/check-game-distribution-ops-rollback-e2e.mjs` 补四条断言:压缩 + `Vary`、强 ETag、`If-None-Match` → 304(无正文)、不接受 gzip 时不压缩。 ## 验证 | 命令 | 结果 | | --- | --- | | `cargo test -p api-server --bin api-server -- game_distribution` | 49 passed(含 5 条新增:ETag 作用域、`If-None-Match` 列表/弱校验/`gzip;q=0`、文本压缩与二进制/小文件不压、304 无正文与 `*` 对缺失路径 404) | | `npx vitest run packages/shared/src/components/PlatformGameLoadingSurface.test.tsx src/components/game-distribution/GameDistributionPages.test.tsx apps/admin-web/src/pages/AdminGameDistributionReviewPage.test.tsx` | 51 passed | | `npm run check:game-distribution-ops-rollback-e2e` | 47 PASS(真实栈 + 真实 OSS,含本轮四条新断言) | | `npm run typecheck` / admin-web typecheck / `npm run check:encoding` / `git diff --check` | 通过 | | 真实浏览器 smoke | 用户端与后台端加载面/画面截图(见下),链路 4 Mbps 模拟 | ## 自查(Review 轮次) 本轮 review 发现 7 处问题(2 处会让 CI 变红)并全部修复:Rust 未过 `cargo fmt`、ESLint 4 处(含共享组件文件同时导出常量触发 `react-refresh/only-export-components`)、主规范未同步发行缓存契约、nginx README 与 Pingora 口径自相矛盾、后台超时态仍转圈且 `aria-busy` 为 true、`Q=0` 大小写、pitfalls 措辞;并按实测把大文件压缩从 level 6 降到 level 1。逐条证据与「复核过无问题」的结论见下方评论。 ## 边界与不做项 - 不改 `publicationRevision`、审核 CAS、`/games/<gameId>/` 路由、Cookie 拒绝与 `sandbox="allow-scripts"` 口径。 - 边缘 gzip/Brotli 与本层不冲突(两边都以「响应已带 `Content-Encoding` 就跳过」收口);Pingora 网关在自身压缩关闭时会移除 `accept-encoding`,那种部署形态下源站压缩不生效,属于网关侧口径,本次不改。 - 一次性实测/截图探针脚本不入库(`.tmp/` 为 gitignored)。 ## 截图(真实 Chromium,4 Mbps 模拟链路) 用户端加载面(改后): ![用户端加载面](https://git.genarrative.world/git/attachments/aa9ca146-47c7-4baa-aff9-4956a066981d) 用户端画面就绪: ![用户端画面](https://git.genarrative.world/git/attachments/b517e36c-8f84-446f-858b-0f246793cc71) 后台试玩加载面(改前这里是全白空白、没有任何文案): ![后台试玩加载面](https://git.genarrative.world/git/attachments/7ca1d62c-777b-4fbd-b480-ef32846faae2) 后台试玩画面就绪: ![后台试玩画面](https://git.genarrative.world/git/attachments/e5b52f07-5341-40d0-9754-cbd09852969b)
suzmii added the Kind/Bug
Priority
Medium
3
labels 2026-10-05 17:30:48 +08:00
suzmii self-assigned this 2026-10-05 17:30:48 +08:00
suzmii added 2 commits 2026-10-05 17:30:48 +08:00
- packages/shared 新增共享游戏加载面 PlatformGameLoadingSurface:封面/标题 + 动效进度 + 按时长推进的阶段文案(准备/资源/引擎)+ 慢加载提示,附用例
- 网页游玩页用共享加载面替换近黑壳上的一行小字,加载上限改为共享常量 PLATFORM_GAME_LOADING_TIMEOUT_MS
- 后台审核试玩补加载面、20 秒超时与「重新创建试玩会话」入口,新会话重置加载态;补两条用例
- 发行网关(api-server)对文本类发行资源按 Accept-Encoding 下发 gzip,并下发强 ETag、命中 If-None-Match 返回 304;补 5 条 Rust 用例
- E2E 脚本 check-game-distribution-ops-rollback-e2e 补压缩/Vary/ETag/304/不接受 gzip 四条断言
- 同步 pitfalls、开发运维文档、nginx README 与两份里程碑记录
补正 pitfalls 里的实测数字:gzip 后 phaser.min.js 为 353,336 B,并记录两侧画面耗时对照
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
f58f51052c
suzmii added 1 commit 2026-10-05 18:03:46 +08:00
修复自查发现的门禁与体验问题:格式、超时态语义、压缩 CPU 边界
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m48s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m3s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m33s
Project CI / Frontend tests (pull_request) Successful in 3m24s
Project CI / Backend tests (pull_request) Successful in 7m29s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m55s
Project CI / Repository checks (pull_request) Successful in 6m33s
Project CI / Native shell tests (pull_request) Successful in 9m0s
d7c4f82d7d
- 新增 Rust 测试补齐 cargo fmt;ESLint 按仓库约定收口:常量与解析函数拆到 platformGameLoadingSurfaceModel.ts,删除 GAME_PLAY_STARTUP_TIMEOUT_MS 常量别名(测试直接用共享常量)
- 共享加载面新增 stalled:宿主判定等待不再推进时停掉进度动画并把 aria-busy 置回 false(去掉与 role=status 重复的 aria-live)
- 后台试玩超时时传入 stalled,避免「一边转圈一边说超时」
- Accept-Encoding 权重参数名改为大小写不敏感(RFC 9110 §12.5.3),GZIP;Q=0 视为拒绝并补用例
- 发行资源压缩分级:≥2 MiB 改用 level 1(zlib 端实测约 1/3 耗时、压缩比差约 3%),小文件仍用 level 6
- 文档:主规范补压缩与条件请求契约(并写明 60 秒窗口与撤销窗口不放宽)、nginx README 修正 Pingora 压缩关闭时的口径、pitfalls 补 CPU 边界与措辞修正
Author
Member

自查结论(Review 轮次,commit d7c4f82d7)

计划:先理解整条链路(用户端加载 → 后台试玩 → 发行网关传输),再逐文件过 diff,最后按整体/边界/门禁收口。

方向与两端口径正确;本轮找出 7 处问题,全部已修并复验(其中 2 处会让 CI 直接变红),另有 4 项判定为「记录不修」。以下每条都给证据与修复。

已修

# 严重度 问题 证据 修复
1 阻断 新增 Rust 测试未过 cargo fmt --check(6 处,全在新增测试) npm run check:rustfmt 报 6 个 diff(源文件 4933–5145) cargo fmt 后 check:rustfmt 绿
2 阻断 ESLint 4 处:simple-import-sort/imports ×2、react-refresh/only-export-components ×2 npx eslint 报 4 error;npm run lint:eslint(--max-warnings 0)是 CI 门禁 按仓库既有约定把常量与解析函数拆到 platformGameLoadingSurfaceModel.ts(对齐 platformPillBadgeModel 等);删除 GAME_PLAY_STARTUP_TIMEOUT_MS 别名(常量别名不是字面量,正是触发那条规则的原因),测试直接用共享常量;eslint --fix 修排序;全仓 lint:eslint 复跑绿
3 重要 主规范未同步:发行缓存契约的权威源是 docs/【玩法创作】平台入口与玩法链路-2026-05-15.md「下架、缓存与运维」,本次给发行网关加了压缩与条件请求,属于该契约 该文件原文只有 no-store + 浏览器/CDN 有效期 ≤60 秒的约束 补一条:gzip+Vary、强 ETag 与 304,并写明 max-age=60, must-revalidate 与撤销窗口都不放宽;check:doc-index 仍通过
4 重要 deploy/nginx/README.md 自相矛盾:「关闭边缘压缩的 Pingora 模式」下用户字节与生产一致——实际那种模式会移除 Accept-Encoding,源站也不会压 pingora-gateway 的 normalize_accept_encoding_for_gateway_compression(压缩关闭时 remove_header);pitfalls 里写对了、README 写反了 README 改成与 pitfalls 一致的表述并指向该条目
5 次要 后台超时态「一边转圈一边说超时」,且仍声明 aria-busy=true 加载面文案换成「试玩版本加载超时」后,进度动画与 aria-busy 没变 共享组件加 stalled:停掉扫动动画、aria-busy=false、压暗填充;后台超时时传入;补用例
6 次要 Accept-Encoding 权重参数名大小写不敏感(RFC 9110 §12.5.3),GZIP;Q=0 被当成「接受」 原实现只匹配小写 q= 改为大小写不敏感解析;用例补 gzip;Q=0、GZIP;Q=0.000
7 次要 pitfalls 词不达意「镜像/音频/视频」 原文 改为「图片/音频/视频」

已复核、判定无问题(附证据)

  • ETag 正确性:ETag 是 (versionId, 资源路径) 摘要,不是字节摘要,前提是「冻结后同版本同路径字节不变」。核对:reset_package_upload 只允许未确认版本重置(注释与实现一致);上传对已存在且长度不同的对象返回 409 PACKAGE_OBJECT_MISMATCH,长度相同则跳过;发行网关只服务 published。→ 不会出现「同 ETag 不同字节」。
  • 304 不放宽撤销窗口:条件请求在解析公开版本之后判定;If-None-Match: * 对包内不存在的路径仍 404(有用例);换版 → ETag 变 → 200;下架 → 404。max-age/must-revalidate 未动。
  • 边缘不二次压缩:Pingora should_allow_gateway_compression_for_response 只在 200 且响应无 Content-Encoding 时压;nginx 同理;两者的 304/206 都不压。
  • 未动语义:后台试玩仍 no-store 且无 ETag;sandbox、Cookie 403、CSP/CORP/CORS 不变(check:game-distribution-ops-rollback-e2e 47 PASS)。
  • 门禁:check:encoding、check:doc-index、check:production-ops、check:nginx-spa-routes、check:pingora-route-parity、check:game-distribution-dto-parity、check:preview-deployer、check:maintenance-page、check:npm-workspaces、check:spacetime-schema、check:rustfmt、typecheck(含 admin-web 口径)、lint:eslint 全绿。

记录不修(含理由)

  1. 每次请求实时 gzip 的 CPU:release 构建实测 level 6 为 1.3 MiB→10 ms、8 MiB→59 ms、64 MiB(单文件上限)→522 ms。已按此改成分级:≥2 MiB 用 level 1(zlib 端实测约 1/3 耗时、压缩比只差约 3%),小文件仍 level 6;并把「优先缓存压缩结果而不是继续放宽级别」写进 pitfalls。
  2. identity;q=0(客户端明确拒绝 identity)时对 <1 KiB 文本仍发 identity:严格说该压或 406。现实客户端不发这种组合,未改。
  3. 浏览器级待验证:60 秒窗口之后浏览器是否真的以 304 复用(服务端 304 由 ops E2E 断言,首次加载已在 Chromium 实测;二次访问未逐帧实测)。
  4. 本地两条门禁红:check:git-hooks(Windows 临时目录 EBUSY)与 check:generated-bindings(worktree 缺未入库的 claude-agent 随包资源)——在 master 上同样红,与本 PR 无关;CI 以 PR 上的 Project CI 为准。
## 自查结论(Review 轮次,commit `d7c4f82d7`) > 计划:先理解整条链路(用户端加载 → 后台试玩 → 发行网关传输),再逐文件过 diff,最后按整体/边界/门禁收口。 方向与两端口径正确;本轮找出 **7 处问题,全部已修并复验**(其中 2 处会让 CI 直接变红),另有 4 项判定为「记录不修」。以下每条都给证据与修复。 ### 已修 | # | 严重度 | 问题 | 证据 | 修复 | | --- | --- | --- | --- | --- | | 1 | 阻断 | 新增 Rust 测试未过 `cargo fmt --check`(6 处,全在新增测试) | `npm run check:rustfmt` 报 6 个 diff(源文件 4933–5145) | `cargo fmt` 后 `check:rustfmt` 绿 | | 2 | 阻断 | ESLint 4 处:`simple-import-sort/imports` ×2、`react-refresh/only-export-components` ×2 | `npx eslint` 报 4 error;`npm run lint:eslint`(`--max-warnings 0`)是 CI 门禁 | 按仓库既有约定把常量与解析函数拆到 `platformGameLoadingSurfaceModel.ts`(对齐 `platformPillBadgeModel` 等);删除 `GAME_PLAY_STARTUP_TIMEOUT_MS` 别名(常量别名不是字面量,正是触发那条规则的原因),测试直接用共享常量;`eslint --fix` 修排序;全仓 `lint:eslint` 复跑绿 | | 3 | 重要 | 主规范未同步:发行缓存契约的权威源是 `docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`「下架、缓存与运维」,本次给发行网关加了压缩与条件请求,属于该契约 | 该文件原文只有 `no-store` + 浏览器/CDN 有效期 ≤60 秒的约束 | 补一条:gzip+`Vary`、强 ETag 与 304,并写明 `max-age=60, must-revalidate` 与撤销窗口都不放宽;`check:doc-index` 仍通过 | | 4 | 重要 | `deploy/nginx/README.md` 自相矛盾:「关闭边缘压缩的 Pingora 模式」下用户字节与生产一致——实际那种模式会移除 `Accept-Encoding`,源站也不会压 | `pingora-gateway` 的 `normalize_accept_encoding_for_gateway_compression`(压缩关闭时 `remove_header`);pitfalls 里写对了、README 写反了 | README 改成与 pitfalls 一致的表述并指向该条目 | | 5 | 次要 | 后台超时态「一边转圈一边说超时」,且仍声明 `aria-busy=true` | 加载面文案换成「试玩版本加载超时」后,进度动画与 `aria-busy` 没变 | 共享组件加 `stalled`:停掉扫动动画、`aria-busy=false`、压暗填充;后台超时时传入;补用例 | | 6 | 次要 | `Accept-Encoding` 权重参数名大小写不敏感(RFC 9110 §12.5.3),`GZIP;Q=0` 被当成「接受」 | 原实现只匹配小写 `q=` | 改为大小写不敏感解析;用例补 `gzip;Q=0`、`GZIP;Q=0.000` | | 7 | 次要 | pitfalls 词不达意「镜像/音频/视频」 | 原文 | 改为「图片/音频/视频」 | ### 已复核、判定无问题(附证据) - **ETag 正确性**:ETag 是 `(versionId, 资源路径)` 摘要,不是字节摘要,前提是「冻结后同版本同路径字节不变」。核对:`reset_package_upload` 只允许**未确认**版本重置(注释与实现一致);上传对已存在且长度不同的对象返回 409 `PACKAGE_OBJECT_MISMATCH`,长度相同则跳过;发行网关只服务 `published`。→ 不会出现「同 ETag 不同字节」。 - **304 不放宽撤销窗口**:条件请求在解析公开版本之后判定;`If-None-Match: *` 对包内不存在的路径仍 404(有用例);换版 → ETag 变 → 200;下架 → 404。`max-age`/`must-revalidate` 未动。 - **边缘不二次压缩**:Pingora `should_allow_gateway_compression_for_response` 只在 200 且响应无 `Content-Encoding` 时压;nginx 同理;两者的 304/206 都不压。 - **未动语义**:后台试玩仍 `no-store` 且无 ETag;`sandbox`、Cookie 403、CSP/CORP/CORS 不变(`check:game-distribution-ops-rollback-e2e` 47 PASS)。 - **门禁**:`check:encoding`、`check:doc-index`、`check:production-ops`、`check:nginx-spa-routes`、`check:pingora-route-parity`、`check:game-distribution-dto-parity`、`check:preview-deployer`、`check:maintenance-page`、`check:npm-workspaces`、`check:spacetime-schema`、`check:rustfmt`、`typecheck`(含 admin-web 口径)、`lint:eslint` 全绿。 ### 记录不修(含理由) 1. **每次请求实时 gzip 的 CPU**:release 构建实测 level 6 为 1.3 MiB→10 ms、8 MiB→59 ms、64 MiB(单文件上限)→522 ms。已按此改成分级:`≥2 MiB` 用 level 1(zlib 端实测约 1/3 耗时、压缩比只差约 3%),小文件仍 level 6;并把「优先缓存压缩结果而不是继续放宽级别」写进 pitfalls。 2. **`identity;q=0`**(客户端明确拒绝 identity)时对 <1 KiB 文本仍发 identity:严格说该压或 406。现实客户端不发这种组合,未改。 3. **浏览器级待验证**:60 秒窗口之后浏览器是否真的以 304 复用(服务端 304 由 ops E2E 断言,首次加载已在 Chromium 实测;二次访问未逐帧实测)。 4. **本地两条门禁红**:`check:git-hooks`(Windows 临时目录 EBUSY)与 `check:generated-bindings`(worktree 缺未入库的 `claude-agent` 随包资源)——在 master 上同样红,与本 PR 无关;CI 以 PR 上的 Project CI 为准。
Author
Member

image.png
image.png
lgtm

![image.png](/attachments/917768e8-f971-42f0-adf9-b8653facd2ed) ![image.png](/attachments/a00936b2-a008-4445-a400-b6e40fa8d024) lgtm
suzmii merged commit fa42cdb139 into master 2026-10-05 19:13:45 +08:00
suzmii deleted branch fix/game-play-loading 2026-10-05 19:13:45 +08:00
Sign in to join this conversation.