Merge remote-tracking branch 'origin/master' into fix/agc-composer-layout
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 5m24s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m14s
Project CI / Frontend tests (pull_request) Successful in 3m48s
Project CI / Backend tests (pull_request) Successful in 8m5s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m0s
Project CI / Repository checks (pull_request) Successful in 7m30s
Project CI / Native shell tests (pull_request) Successful in 9m44s
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 5m24s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m14s
Project CI / Frontend tests (pull_request) Successful in 3m48s
Project CI / Backend tests (pull_request) Successful in 8m5s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m0s
Project CI / Repository checks (pull_request) Successful in 7m30s
Project CI / Native shell tests (pull_request) Successful in 9m44s
合并 master be9f74f42(付费游玩泥点付费规范 #635 等):保留双方条目/内容 - 唯一冲突:`docs/project-memory/shared-memory/pitfalls.md` —— 本分支 2 条(2026-10-05「PR #607 复核修复」+「模型菜单的观感是组件自带的共享样式面」)在前,master 新增 2 条(「给 shared-contracts 请求 DTO 加字段」+「付费游戏播放会话前缀落在 /api/*」)紧随其后,**两侧 4 条都保留**(grep 逐条命中 1) - 其余 286 个文件自动合并(master 侧含 server-rs / admin-web / 主站 / vite.config.ts 等,与本分支不重叠;`styles.css` 也是自动合并、无冲突) - 门禁(本轮只合并、未改内容):`vitest run appSurface + chatDialogFrameLayout + conversationModelSelect` **258 passed / 9 skipped**;`npm run agc:typecheck` pass 3 / fail 0;`npm run check:encoding` 5418 files;`git diff --check` rc=0;prettier 已对合并后的 pitfalls 重新折行
This commit is contained in:
@@ -1,5 +1,16 @@
|
||||
# 决策记录
|
||||
|
||||
## 2026-10-05 播放会话前缀在三处入口清空 Cookie,网关 403 纵深防御不变
|
||||
|
||||
- 背景:付费游戏的可玩入口是创建播放会话后拿到的 `/api/game-distribution/play-sessions/<token>/`(sandbox iframe 的 `src`,包内相对资源沿同一前缀解析)。该前缀落在 `/api/*` 上,边缘通用 `/api` location 必须转发 Cookie(`/api/auth/*` 需要 refresh cookie),而 `api-server` 播放网关对带可解析平台 refresh Cookie 的请求返回 403,导致真实浏览器里 iframe 与每个包内资源都 403、付费游戏实际不可玩。
|
||||
- 决策(边缘):三份 nginx 模板(`deploy/nginx/genarrative.conf`、`deploy/nginx/genarrative-dev-http.conf`、`deploy/container/nginx.conf`)在通用 `/api` location 之前内联 `location ^~ /api/game-distribution/play-sessions/`;代理头、`client_max_body_size 210m`、`limit_conn` / `limit_req`、超时与维护判断与通用 `/api` 保持一致,额外清空 Cookie。`^~` 必填(否则正则 location `~ ^/api(?:/|$)` 优先命中),且只匹配带尾斜杠的前缀。
|
||||
- 决策(dev):`vite.config.ts` 在 `/api/game-distribution` 之前加同名前缀代理规则,`proxyReq.removeHeader('cookie')`。
|
||||
- 决策(网关):`server-rs/crates/pingora-gateway` 新增 `RouteDecision::PlaySessionGateway`,与通用 `/api` 同口径(api 上游、api 限流分组、大小上限、维护闸),差别只在经新增的 `route_clears_cookie` 清空 Cookie(发行入口 `ReleaseGateway` 复用同一判定)。**不放宽** `api-server` 的 Cookie 拒绝。
|
||||
- 决策(边界):前缀只认带尾斜杠的形式,创建会话的 `POST /api/game-distribution/play-sessions` 与 `POST /api/game-distribution/games/{gameId}/play-session` 继续走通用 `/api` 并保留 Cookie。
|
||||
- 门禁:矩阵新增 `play_sessions_gateway` 用例;`check:nginx-spa-routes` 新增「该前缀 location 存在、清空 Cookie、排在通用 `/api` 之前」断言,`check:pingora-route-parity` 新增「矩阵用例必须声明清 Cookie 且不得复用通用 `/api` location / Rust 播放会话分支必须排在通用 `/api` 之前」断言,`check:pingora-gateway-smoke` 新增真实网关下「该前缀清 Cookie、创建会话端点保留 Cookie」用例。
|
||||
- 影响面:`deploy/nginx/{genarrative.conf,genarrative-dev-http.conf,README.md}`、`deploy/container/nginx.conf`、`vite.config.ts`、`server-rs/crates/pingora-gateway/src/main.rs`、`deploy/pingora/nginx-route-parity.matrix.json`、`scripts/check-{nginx-spa-routes,pingora-route-parity,pingora-gateway-smoke}.mjs`、`docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
- 关联:`docs/project-memory/shared-memory/pitfalls.md`「付费游戏播放会话前缀落在 `/api/*`」条。
|
||||
|
||||
## 2026-10-03 每日免费发放额为 0 时前端隐藏该池
|
||||
|
||||
- 背景:运营需要一个可逆的「不提供每日免费泥点」状态。不给它新增 `retired` 状态位或新字段,直接把后台配置 `daily_free_points_per_day` 配成 0,让「每日免费发放额」这个普通数值自己表达;前端据此隐藏每日免费相关入口。
|
||||
@@ -9,7 +20,6 @@
|
||||
- 影响范围:`packages/shared/src/utils/mudPoints.ts`、`PlatformMudPointWalletEntry`、`PlatformProfileRechargeModal`(池概览 3 列变 2 列、扣点顺序提示与泥点确认页文案随可见性切换)、`apps/admin-web/src/pages/AdminProfileWalletConfigPage.tsx`(每日免费允许填 0)、`server-rs/crates/module-runtime/{commands,errors,lib}.rs`;`daily_free_grant` / `daily_free_reset` 账本文案保留,历史流水不改写。
|
||||
- 验证:`cargo check -p module-runtime`、`cargo test -p module-runtime profile_wallet_config_allows_zero_daily_free_points`、`cargo fmt --check`、根 `npm run typecheck`、`npm run admin-web:typecheck`、共享层与 admin 定向 vitest 22/22、`npm run check:encoding`、`git diff --check` 通过。
|
||||
|
||||
|
||||
## 2026-10-05 创作者主页与关注粉丝的产品边界
|
||||
|
||||
- 产品已确认:桌面第四项“创作者主页”默认进入当前账号主页,“我的”移到第五项;他人的关注/粉丝列表公开可查看,自己或他人的两类列表均可点击用户进入其创作者主页。
|
||||
|
||||
@@ -23,6 +23,24 @@
|
||||
- **后续(同一批收口)**:强度区与外壳锚点也一并抬到共享面——`view/home/index.tsx` 给首页那颗传了**同一个** `ComposerReasoningEffortSelect`(`presentation="section"`,读写仍是组件自己的 `read_game_creator_app_config` / `select_game_creator_reasoning_effort`),首页因此与工作台逐项同形:外壳 260×262.5、强度区 234×60.5、列表 234×170、滑块 222×26(447 与 1200 两档实测一致;工作台回归后逐值不变)。抬升时必须删掉工作台作用域里两条**死重**规则(给旧独立「推理档」控件排版的 `display: inline-flex` 一族),否则它们会以更高特异性盖掉共享面的 `display: grid`,把强度区重新算宽 24px。
|
||||
- **滑块两点(最终收口)**:档位圆点先是改成派生浅暖色、直径收到 6px(= 轨道高度),随后**整体删除**(见上面 D1 条)。「进度条高度与滑块高度一致」保留两种解释对照:**变体 A 落地**(填充段 = 轨道高度 6px),**变体 B**(填充段做成 20px = 圆钮高度)只在夹具里渲染出图、未提交。
|
||||
|
||||
## 2026-10-05 给 `shared-contracts` 请求 DTO 加字段:`#[serde(default)]` 救不了 Rust 结构体字面量,AGC 壳编译失败会伪装成 `npm run dev:all` 起不来
|
||||
|
||||
- **现象**:`npm run dev:all` 的根栈五个服务与 AGC Vite 都就绪、终端也会打印启动汇总,但 AGC 窗口始终不出现;stdout 里夹着 `error[E0063]: missing field `price_mud_points`in initializer of`GameDistributionCreateVersionRequest``(`src\game_distribution_publish.rs:1356`)和 `error: could not compile `genarrative-ai-game-creator-shell` (bin ...) due to 1 previous error`。编译失败不会让 `tauri dev` 退出,dev:all 只会一直挂着(`waitForAgcFrontend` 的 660s 预算耗尽后才收束整棵树),容易被误判成端口占用或根栈没起来。
|
||||
- **根因**:变更在 `server-rs/crates/shared-contracts/src/game_distribution.rs` 给请求 DTO 末尾追加了 `#[serde(default)] pub price_mud_points: u64`。`serde(default)` 只影响**反序列化缺字段**,Rust **结构体字面量仍必须列全字段**。AGC 壳 `apps/ai-game-creator-shell/src-tauri` 是**独立 cargo workspace**(自带 `[workspace]`,只把 `shared-contracts` 当 path 依赖),`server-rs` 侧的 `cargo test -p ...` 六个 crate 全绿也覆盖不到它。
|
||||
- **处理(现行口径)**:改 `shared-contracts` 里**请求 DTO 字段**时,必须同一次编译 AGC 壳:先 `npm run agc:bundled-resources:prepare`(`build.rs` 只做只读校验,未准备资源会以「随包插件存在未声明文件」失败关闭),再 `cargo check --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --features=cocos-editor-execute,unity-editor-execute,godot-editor-execute`(约 30s,feature 与 dev/release 对齐);完整口径是 `npm run ai-game-creator-shell:check:rust`。定价字段的取值口径分两段:**历史口径**(2026-10-05 之前)AGC 发布面板没有买断制定价入口,构造版本请求时显式按免费提交 `price_mud_points: 0`,与升级前行为一致;**现行口径** AGC 发布面板已支持「免费 / 买断制」定价,请求按作者选择从载荷透传价格,`#[serde(default)]` 仅用于向后兼容不传该字段的旧客户端(按免费处理)。
|
||||
- **边界**:`cargo check` **不能省 feature 参数**——默认 feature 下 `build.rs` 会因为已 staging 的 godot/unity 插件 DLL「不在当前 feature 组合的声明清单里」而红,那是资源准备前置条件,不是本次代码的编译错误。门禁本身**已经存在**:CI `.gitea/workflows/project-ci.yml` 的 `AI game creator shell Rust lane 1/2`、`lane 2/2` 各顺序跑两片 `npm run check:native-shells:agc-rust-shard-N`(底层 `ai-game-creator-shell:check:rust:shell` → `cargo test --locked` 编出壳 bin),本地同序列是 `npm run check:native-shells`。漏拦的原因是本地验证只跑了 `server-rs` 侧 crate、没等 MR/CI 上的 AGC lane,不是缺门禁;因为 2466 条 bin 单测跑满很贵,**不要**把整条 lane 塞进常用本地命令,只在改动 shared-contracts 请求 DTO 时补上面的 `cargo check`。
|
||||
- **判据/取证**:E0063 原文(`logs/dev-all-feature.log`);修复后 `tauri dev` watcher 重建输出 `Finished `dev` profile [unoptimized + debuginfo] target(s) in 38.16s` 并拉起 `target\debug\genarrative-ai-game-creator-shell.exe`;同一 feature 组合 `cargo check` 退出码 0;`.app/dev-stack.json` 记录的实际端口下 api-server `/healthz`、主站 `/`、admin-web `/admin/`、AGC marker `/__agc_dev_server.json` 均 200。
|
||||
- **关联**:`server-rs/crates/shared-contracts/src/game_distribution.rs`、`apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs`、`.gitea/workflows/project-ci.yml`、`scripts/check-native-shells.mjs`。
|
||||
|
||||
## 2026-10-05 付费游戏播放会话前缀落在 `/api/*`:边缘转发 Cookie 会让 iframe 与包内每个资源都 403
|
||||
|
||||
- **现象**:付费游戏在真实浏览器里打不开——播放会话 `src`(`/api/game-distribution/play-sessions/<token>/`)本身和包内每个相对资源(JS/CSS/图片/音频)全是 403,同一份包的免费游戏 `/games/<gameId>/` 正常。
|
||||
- **原因**:播放会话前缀落在 `/api/*` 上,而通用 `/api` location 必须转发 Cookie(`/api/auth/*` 依赖 refresh cookie);`api-server` 播放网关对带**可解析平台 refresh Cookie** 的请求返回 403(与发行网关同族的纵深防御,本次不放宽),于是沙箱 iframe 的每个同前缀请求都带 Cookie、都被拒。dev 侧同样复现:`vite.config.ts` 原本只对 `/games/...` 清 Cookie,`/api/game-distribution` 规则会转发 Cookie。
|
||||
- **处理(现行口径)**:三份 nginx 模板(`deploy/nginx/genarrative.conf`、`deploy/nginx/genarrative-dev-http.conf`、`deploy/container/nginx.conf`)在通用 `/api` location **之前**加 `location ^~ /api/game-distribution/play-sessions/`——`^~` 不能省,否则正则 location `~ ^/api(?:/|$)` 优先命中、Cookie 又被转发;代理头 / `client_max_body_size 210m` / `limit_conn` / `limit_req` / 超时 / 维护判断都与通用 `/api` 一致,只多一条 `proxy_set_header Cookie ""`。`vite.config.ts` 在 `/api/game-distribution` 之前加同名前缀规则(`proxyReq.removeHeader('cookie')`)。Pingora 侧对应 `RouteDecision::PlaySessionGateway`:路径原样走 api 上游,同样套 api 限流分组、大小上限与维护闸,差别只在新增的 `route_clears_cookie` 清空 Cookie(发行入口 `ReleaseGateway` 复用同一判定)。
|
||||
- **边界**:前缀**只匹配带尾斜杠**的形式——创建会话的 `POST /api/game-distribution/play-sessions`(以及 `POST /api/game-distribution/games/{gameId}/play-session`)需要账号凭证,必须继续走通用 `/api` 并保留 Cookie。网关的 403 拒绝保持不变,只在边缘/dev 保证请求不带 Cookie。
|
||||
- **门禁**:`npm run check:nginx-spa-routes` 对三份模板断言该 `^~` location 存在、块内清空 Cookie、代理头齐全且排在通用 `/api` location 之前(变异验证:删掉块内 `proxy_set_header Cookie "";` 立刻报「播放会话前缀 location 缺少代理片段」);`npm run check:pingora-route-parity` 断言矩阵 `play_sessions_gateway` 用例声明清 Cookie 片段、不复用通用 `/api` location,且 Rust `classify_path` 的播放会话分支排在通用 `/api` 之前(变异验证:把矩阵片段换成通用 location、或在 Rust 里交换两个分支,各自单独判红);`npm run check:pingora-gateway-smoke` 用真实网关二进制断言该前缀清 Cookie、创建会话端点保留 Cookie。三条都串在 `npm run lint` 链里,有自动调用方。
|
||||
- **关联**:`server-rs/crates/pingora-gateway/src/main.rs`、`deploy/pingora/nginx-route-parity.matrix.json`、`deploy/nginx/README.md`、`vite.config.ts`;另见本文件「主站 SPA allowlist 有三处真相源」条的「别踩」(发行入口不转发 Cookie 的同族规则)。
|
||||
|
||||
## 2026-10-05 自定义作者插槽应保留昵称降级语义
|
||||
|
||||
- 游戏公开投影里的「创作者」「未知作者」是角色占位词。作者昵称 hook 已将加载中和查询失败分别转成 null 与空串,宿主不能再用 `|| game.author.name` 把占位词补回。
|
||||
|
||||
Reference in New Issue
Block a user