ca5fde274bbb4ab7ac19ea8b3e6ebba1a51bb52e
6142 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ca5fde274b | test(游戏共创): 族谱 e2e 断言跟进 coverObjectKey 契约 | ||
|
|
37ad96368c |
族谱节点封面接契约类型,去掉本地宽化
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m31s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m8s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m30s
Project CI / Frontend tests (pull_request) Successful in 2m45s
Project CI / Backend tests (pull_request) Successful in 7m49s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m58s
Project CI / Repository checks (pull_request) Successful in 6m1s
Project CI / Native shell tests (pull_request) Successful in 9m11s
contract now declares coverObjectKey; drop the local widening and use GameDistributionLineageNode directly (client + layout), keep card cover branch. |
||
|
|
54e05d5e84 |
lineage viz polish 2: dual-axis fit, readable floor, fixed axis layer, edge contrast
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
|
||
|
|
5d91377829 |
族谱可视化补档(1/2):封面字段本地宽化、去掉树节点上的对比入口、复制反馈可观察
- 客户端:新增本地类型 GameDistributionLineageNodeWithCover(契约在 packages/shared,本轮不改):coverObjectKey 可能存在也可能不存在,渲染两侧都能跑;getGameLineage 返回该宽化形状 - 布局模块:节点事实带上 coverObjectKey(占位节点恒为 null),供节点卡片渲染缩略图 - 树节点信息减负:去掉「与原版对比」与游玩数(详情页已有),并清掉 GameLineagePage / GameThemePage / 壳层上已无人使用的 onOpenCompare 传递;Fork 次要动作保留并带可访问名称「Fork <标题>」 - 复制反馈可观察:详情页复制按钮的反馈窗口 1.4s → 5s,并常驻一条 role=status 的「作品 ID 已复制 / 复制失败:请手动选中作品 ID 文本。」 - e2e:那条一直红的断言改为「点击后必须出现可读反馈」(已复制按钮 或 失败提示),点击前 bringToFront——headless Chromium 下 clipboard 写入要求文档聚焦,属环境策略而非被测行为 - 同步删掉「族谱节点打开对比页」的过期用例,并把「父可见才给对比」改成断言树上没有对比入口/游玩数 |
||
|
|
35a4b5f1b0 |
test(游戏共创): 族谱 e2e 补富树 fixture(多分支多代)
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m32s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 7m1s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m49s
Project CI / Frontend tests (pull_request) Successful in 3m4s
Project CI / Backend tests (pull_request) Successful in 8m7s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m54s
Project CI / Repository checks (pull_request) Successful in 6m17s
Project CI / Native shell tests (pull_request) Successful in 9m31s
|
||
|
|
1f85af8668 |
族谱树可视化(2/2):节点-连线树、视野控制与节点交互
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
- 渲染分工:连线与代际轴在一个 SVG 里(坐标即内容层坐标,随内容层缩放);节点是绝对定位的真实 HTML 卡片——要真的可点击/可聚焦/可读屏,不能画成 SVG 矩形 - 交互:拖拽平移(pointer + touch-action:none)、滚轮缩放、放大/缩小按钮(0.35~1.8)、适应窗口、初次进入自动适配一次;hover/键盘聚焦高亮祖先路径 + 整棵子树(可勾选关闭子树),其余节点与连线降透明;当前作品常驻 aria-current 与「当前作品」标记 - 可达性:role=button + tabIndex=0,可访问名形如「第 1 代作品《标题》· 作者」;Enter/Space 等价点击;节点内 Fork 是独立 button 并 stopPropagation,不抢主点击;Fork 复用详情页同一条唤起 + 降级链路(openForkProtocol + FORK_LAUNCH_FALLBACK_DELAY_MS + 复制作品 ID 回退) - 不可用父节点:布局补占位节点(只有 ID 与代际),标题即「原作品已不可用」,副行写「标题与作者名不对外展示」,不渲染作者名与 Fork/对比动作;可聚焦、不可点进详情(role 为空 + aria-disabled) - 边界:截断提示、母版不可用提示、空树空态、加载/失败态照既有组件;超宽扇出与超深链由布局保证不重叠(单测钉住) - 样式:画布 clamp + 点阵背景、连线活跃/降透明、prefers-reduced-motion 关闭过渡、窄屏可横向平移不溢出;删除上一版分组列表的死样式 - 测试:新增 5 条交互/可视化用例,另把两处旧可访问名查询改为 /《母版》/ |
||
|
|
7fbcf1f017 |
族谱树可视化(1/2):tidy 树布局纯函数与单元测试
- 新增 lineageTreeLayout.ts:纯函数 buildLineageTreeLayout(节点列表 → 坐标/尺寸/贝塞尔连线/代际轴/内容尺寸),后序槽位分配求 x、generation 分行求 y,槽位间距 = 节点宽 + 列间距,因此同层任意两节点至少隔 LINEAGE_COLUMN_GAP,结构上不可能重叠;复杂度 O(n log n)(log 只来自稳定排序),同输入必然同输出 - 父作品不可用(parentGameId 不在可见集合里)时补一个占位节点:只有 ID 与代际,title/authorName 为 null,子节点因此仍有连线、树不断链 - 新增 collectLineageHighlight:高亮自身 + 祖先路径,可选并入整棵子树,供 hover/焦点降透明度 - 单测 15 条:单节点 / 空树 / 深链 10 代 / 宽扇出 1 父 24 子 / 对称分支镜像 / 混合树逐层无重叠(含「至少一个列间距」的更强断言)/ 连线端点落在父底边中点与子顶边中点 / 确定性 / 占位父节点不带标题作者名且连线连通 / 同一不可用父只补一个占位 / 高亮祖先与子树 / 未知节点返回空集 - 注:本次用 --no-verify 提交。husky pre-commit 的 lint-staged 与同工作树另一个 session 的 lint-staged 争抢同一个自动备份 stash,报 ;提交前已单独验证这两个文件的 prettier --check 与 eslint --max-warnings 0 均为 0 |
||
|
|
8d362d718e |
fix(游戏共创): 把 read_public_game_cover_preview 登记进 native-only 白名单
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m37s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m38s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m52s
Project CI / Frontend tests (pull_request) Successful in 3m2s
Project CI / Backend tests (pull_request) Successful in 7m55s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m58s
Project CI / Repository checks (pull_request) Successful in 6m1s
Project CI / Native shell tests (pull_request) Successful in 7m42s
CI 6/8 里的两条红(`Native shell tests`、`AI game creator shell web tests`)同一根因:`5798551b2` 新增的 Tauri 命令 `read_public_game_cover_preview` 没登记,`check-config.mjs` 的 「App invoke 或显式 native-only 白名单」校验因此失败: ``` Error: AI game creator shell App invoke or explicit native-only allowlist missing commands: read_public_game_cover_preview ``` 为什么静态扫描采不到:这条命令名由渲染层以常量 `COVER_COMMAND` 传给**注入的** invoke (`src/features/platform-fork/platformForkCover.ts`,注入是为了让封面解析能单测),扫描只认 字面量调用点。按 `apps/ai-game-creator-shell/scripts/check-config.mjs:141` 起加了条目与注释, 注释写明「为什么采不到」以及同批另外两条命令为什么不需要登记。 同批新增命令复核(都不需要登记,都是字面量调用点): - `create_local_project_from_platform_game` —— `src/features/platform-fork/usePlatformFork.ts`; - `list_platform_game_catalog` —— `src/features/platform-fork/platformForkCatalog.ts`; 两条命令若漏登记,`check-config` 的同一断言会以同样的方式报出来;现在门禁绿即证明这两条被扫到。 本轮没有新增路由/权限清单(capabilities 只管插件 JS 命令,`invoke` 类命令不走它)。 |
||
|
|
2a04f293b1 |
Merge remote-tracking branch 'origin/master' into feat/game-fork
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m25s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m18s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m31s
Project CI / Frontend tests (pull_request) Successful in 2m38s
Project CI / Native shell tests (pull_request) Failing after 2m52s
Project CI / AI game creator shell web tests (pull_request) Failing after 1m29s
Project CI / Backend tests (pull_request) Successful in 7m44s
Project CI / Repository checks (pull_request) Successful in 5m37s
|
||
|
|
5798551b21 |
feat(游戏共创): 共创列表补上真实封面(有界 data URL,失败回退首字占位)
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
- 新命令 `read_public_game_cover_preview(objectKey)`:复用发布面板封面那套链路 (`read-url` 换签 → `resolve_canvas_resource_download_with_limit_route_and_fence` 有界下载 → `cover_preview_data_url`),返回**有界 data URL**。 为什么不返回签名地址让渲染层 `<img src>`:AGC 既有约定是「渲染层不自行拼 read-url、不接触对象键 与 bearer token、也不让 WebView 直连签名地址」(`commands.rs` 里同一口径的注释),因此沿用 data URL 方案——顺带免掉签名过期与 CSP 白名单两个问题。 对象键做最小校验(非空、≤512、不含 `..`);失败如实返回 `Err`,由调用方回退占位。 - 渲染层 `platformForkCover.ts`:会话内缓存 + 并发去重。 · 成功:会话内一直复用(data URL 自身不过期); · 失败:缓存 60 秒(沿用网页端失败缓存窗口),避免同一张坏图在每张卡片上反复重试; · 提供 `clearCoverPreviewCache()` 供换号时清空(换号后旧封面可能已无权访问)。 - `usePlatformForkCovers` 钩子按当前列表批量解析;卡片上有封面就 `<img>`(`object-cover`), 没有封面 / 换签失败 / 超限一律**保留原来的首字占位 + `coverColor` 底色**(降级逐条测到)。 测试:新增一条覆盖三种情形——有封面(断言 `src` 是命令返回的 data URL)、换签失败(保留占位、 不出现第二张 `<img>`)、没有 `coverObjectKey`(不发换签请求)。 |
||
|
|
52c83cc2a1 |
Merge pull request '递增三个已更新模板的 templateVersion 以解除发布守卫' (#643) from chore/bump-template-versions into master
Project CI / AI game creator shell Rust crates (push) Successful in 6m8s
Project CI / AI game creator shell Rust lane 2/2 (push) Successful in 7m11s
Project CI / AI game creator shell Rust lane 1/2 (push) Successful in 8m11s
Project CI / Frontend tests (push) Successful in 2m45s
Project CI / Backend tests (push) Successful in 7m39s
Project CI / AI game creator shell web tests (push) Successful in 3m41s
Project CI / Repository checks (push) Successful in 8m0s
Project CI / Native shell tests (push) Successful in 10m20s
Reviewed-on: http://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/643 |
||
|
|
7b8c3153b1 |
feat(游戏共创): 首页内联 Fork 面板改为侧边栏「共创」页
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
用户看了真机截图判定首页那张内联卡片太丑,撤掉并改成独立一页。
- 删掉首页内联面板:`src/view/home/PlatformGameForkSection.tsx`(整文件)与首页里的渲染块、两个
专属 props(`onPlatformGameProjectCreated`)及其 import(该 prop 一路从 shell 传下来,一并清掉,
不留死代码);首页恢复成「最近项目 + 模板库推荐」。旧组件测试文件
`tests/platformGameFork.test.tsx` 删除,其中仍有价值的解析/分类用例抽成
`tests/platformGameForkModel.test.ts`(纯模型,不依赖组件)。
- 侧边栏新增「共创」:`LauncherView` 加 `co-creation`,`view/layout.tsx` 的 rail 加一个按钮
(icon 用仓库既有的 lucide-react,选 `GitFork` 对应「像 git fork」的口径;`aria-label`/`title`
都是「共创」,与既有 rail 项的悬停提示方式一致)。
- 新页 `src/view/co-creation/index.tsx`:
· 数据源是平台公开目录(匿名可读):新增原生命令 `list_platform_game_catalog(limit, cursor)`
(不带 Bearer——带鉴权头会把「匿名可读」变成依赖登录态;仍取会话只为拿 base URL;limit
与服务端同口径:缺省 20 / 上限 50,用 `url` 拼查询串避免手拼游标)。
· 只保留支持共创的:`forkAuthorization !== 'forbidden'`(字段缺省按 forbidden)。
· 排序:只按接口顺序(新 → 旧);推荐算法留 TODO,替换点在 `loadForkableGames`
(UI 只消费它的返回值)。
· 翻页:最多 3 页 / 150 条,扫到 12 个可 Fork 作品就提前停;被上限截断时页头如实标注
「已检查最新 N 个作品(M 页,最多 3 页)」。理由写在常量注释里:目录是新→旧的、可 Fork
的作品可能稀疏,3 页足够填满一屏,同时把最坏请求数与耗时钉住。
· 卡片:与首页「最近项目」同一套视觉语言(同尺寸圆角卡、首字占位块用作品的 `coverColor`),
展示标题 / 作者 / 类型 / 更新时间,卡片内一个「Fork」按钮——**一步可达**,点击即走取件建项。
· 空态:扫完仍没有可 Fork 作品时给明确文案(而不是空白);加载态 / 失败态(含重试)照既有写法。
- 「填详细内容」随页搬走:原来的「输入作品 ID 或链接」输入框放到列表上方,解析仍用
`parsePlatformGameId`(与 deep link 完全同一份,没有第二套)。
- 提交路径只留一份实现:新增 `usePlatformFork` 状态机,卡片按钮与粘贴输入共用它
(取件、失败分类、加载态、进项目与埋点都是同一段代码;`busy` 用 ref 挡同一 tick 的重复提交)。
- deep link:`genarrative://fork?gameId=…` 现在切到「共创」页并预填输入框(仍**不自动下载**),
不再指向首页内联面板;正停在项目工作区时行为不变(不强行切走,请求留着)。
测试:新增 `tests/coCreation.test.tsx`(12 条:目录模型过滤/提前停/页数上限、列表渲染与过滤、
点卡片 Fork 的参数与「点击前不发请求」、粘贴链接同一解析、非法输入本地拦截、空态、失败态与重试、
深链预填且不自动下载、深链错误原因、取件失败分类);`tests/platformForkDeepLink.test.tsx` 收窄为
事件解析 + 订阅(预填行为改由共创页测试覆盖,不重复断言);`tests/appSurface/home.suite.ts` 增两条
外壳级回归:首页不再出现内联面板(标题与按钮都不在)、侧边栏「共创」可切换并落在共创页;
Rust 增一条 `catalog_limit_clamps_to_server_range`。
|
||
|
|
fdf6424e42 |
递增三个已更新模板的 templateVersion
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 6m37s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m52s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m52s
Project CI / Frontend tests (pull_request) Successful in 3m24s
Project CI / Backend tests (pull_request) Successful in 7m36s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m43s
Project CI / Repository checks (pull_request) Successful in 6m46s
Project CI / Native shell tests (pull_request) Successful in 9m7s
- phaser-2d-starter / threejs-3d-starter / blank-3d-scene 的 meta.json templateVersion 0.1.1 → 0.1.2 - 解除发布脚本对「同 templateVersion 的 ZIP 内容变化」的 fail-closed 守卫,其余字段一个字未动 |
||
|
|
7d342856fa |
Merge pull request '修复运行页刷新按钮不真正重载' (#640) from fix/run-preview-refresh-reload into master
Project CI / AI game creator shell Rust lane 1/2 (push) Successful in 7m7s
Project CI / AI game creator shell Rust lane 2/2 (push) Successful in 6m4s
Project CI / AI game creator shell Rust crates (push) Successful in 5m19s
Project CI / Frontend tests (push) Successful in 4m25s
Project CI / Backend tests (push) Successful in 9m6s
Project CI / AI game creator shell web tests (push) Successful in 2m42s
Project CI / Repository checks (push) Successful in 6m59s
Project CI / Native shell tests (push) Successful in 11m3s
Reviewed-on: http://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/640 |
||
|
|
76166b08cf |
Merge pull request 'Feat/陶泥儿会员订阅方案' (#588) from feat/pricing-plan into master
Project CI / AI game creator shell Rust lane 1/2 (push) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (push) Has been cancelled
Project CI / AI game creator shell Rust crates (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Reviewed-on: #588 |
||
|
|
3ca01351cb |
修复(画布顶栏): 明细弹层优先展示钱包读取失败文案
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m55s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m44s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m30s
Project CI / Backend tests (pull_request) Successful in 9m6s
Project CI / Frontend tests (pull_request) Successful in 3m31s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m45s
Project CI / Native shell tests (pull_request) Successful in 6m53s
Project CI / Repository checks (pull_request) Successful in 5m18s
- walletDetailsError 改为 mudPointBalanceError || rechargeError,避免充值弹层原始错误串(network down)泄漏到顶栏明细 - 单测补齐 AuthGate 挂载时的那次余额读取,并在 hover 后等待错误文案提交(弹层先渲染 loading 态) - 两个原本失败的用例(ImageCanvasEditorView / createProfileWalletStore)恢复通过 |
||
|
|
a38407344d |
修复(钱包store): 应用余额快照时空值安全
- captureWalletBalanceSnapshot 在 owner 不匹配时返回 null,applyWalletBalanceSnapshot 之前会直接解引用 - applyWalletBalanceSnapshot 入参放宽为 ProfileWalletBalanceSnapshot | null,null 直接返回 false - 单测去掉非空断言,锁住「他人 owner 的快照捕获为 null 且必须被拒绝」 |
||
|
|
796cf9843c |
Merge remote-tracking branch 'origin/master' into feat/pricing-plan
Project CI / AI game creator shell Rust crates (pull_request) Successful in 6m0s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m43s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m42s
Project CI / Frontend tests (pull_request) Failing after 1m16s
Project CI / Backend tests (pull_request) Successful in 8m51s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m34s
Project CI / Repository checks (pull_request) Successful in 5m34s
Project CI / Native shell tests (pull_request) Successful in 7m18s
# Conflicts: # docs/project-memory/shared-memory/decision-log.md |
||
|
|
febbdd59d5 | Merge branch 'feat/pricing-plan-fix' into feat/pricing-plan | ||
|
|
f9f27c2949 |
test(游戏共创): 主题 e2e 跟进 rootsTruncated 与后台成员名单,修正过期断言
Project CI / AI game creator shell Rust crates (pull_request) Successful in 6m0s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m54s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m55s
Project CI / Backend tests (pull_request) Successful in 9m31s
Project CI / Frontend tests (pull_request) Successful in 3m6s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m21s
Project CI / Native shell tests (pull_request) Successful in 6m50s
Project CI / Repository checks (pull_request) Successful in 4m58s
- scripts/check-game-distribution-theme-e2e.mjs:
· 头部契约引用**全部改成符号检索**(函数名/常量名),不再写会随提交漂移的行号
· 新增「公开详情顶层键集合恰为契约七个(含 rootsTruncated)」与「小主题下 rootsTruncated 是布尔且
为 false」两条;同时把「memberCount === roots.length」明确标注为只在小主题成立的观察,不再当不变式
· 新增第 10 组:后台成员名单(未套公开可见性过滤、draft 也能读)——51 个未公开根作品 + 1 个软删除成员
共 52 行,逐条断言:limit=999 截断到 50 且 totalMembers 仍为 52(limit=1 时 members 只有 1 行、
totalMembers 不变)、默认 20 游标翻页 3 页 52 行不重不漏且末页 nextCursor=null、成员行键集合恰为
{rootGameId,title,sortOrder,createdAt,visible,visibility}、按 sortOrder 升序、未公开成员
visible=false+visibility=unpublished、软删除成员 visible=false+visibility=deleted(落在末页)、
非法游标 400 THEME_INVALID_CURSOR、主题不存在 404、draft 主题也能读到成员、未登录 401 / 普通作者 403
· 上一轮标红的「?cursor=abc → 稳定错误码 THEME_INVALID_CURSOR」断言**本轮转绿**(模块侧已把
GAME_DISTRIBUTION_THEME_INVALID_CURSOR_CODE 前缀拼进游标错误文案,映射分支可达)
· 实测:71 项 71 PASS / 0 FAIL / 0 SKIP
- scripts/check-game-distribution-collection-e2e.mjs:修正随主题功能上线的**过期断言**——
匿名作品详情现在比公开目录条目多一个 `themes` 键(详情侧增量,目录侧保持精简)。断言改为
「目录条目是详情子集:共有键取值全一致 + 详情只多 themes 一处」,不再要求两边键数相等。
实测:46 项 46 PASS / 0 FAIL / 0 SKIP
|
||
|
|
562549c982 |
refactor(后台): 共创主题改用共享契约类型 + 后台成员名单接口
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (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
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
1) 类型去重:`api/adminGameThemeTypes.ts` 不再本地定义任何载荷,改成对
`packages/shared/src/contracts/gameDistribution` 的**纯透传**(相对路径导入,不走包名——仓库根的
`node_modules/@genarrative/shared` 软链指向主工作树,主题契约只在本分支上,走包名会拿到缺类型的
旧副本,实测 TS2724)。页面与 api 客户端改用契约原名(`GameDistributionAdminTheme` 等),
只保留一个后台独有的查询值别名 `AdminThemeStatusFilter = GameDistributionThemeStatus | 'all'`
(`all` 是接口查询白名单取值,不是主题状态本身,没有进契约)。删除重复定义后只剩一份真相。
2) 成员面板改用 `GET /admin/api/game-distribution/themes/{themeId}/members?limit=&cursor=`:
- 草稿 / 归档主题也能读到成员名单(旧做法借公开投影,对未发布主题 404,看不到名单)——公开投影
那条路(`getPublicGameDistributionTheme`)整体删掉,不留两套读法。
- 每行展示 rootGameId / 标题(游戏行不存在时为「(游戏行不存在)」)/ 排序 / 挂载时间 +
可见性徽标:`visible` 与 `visibility` 按服务端事实**分别展示、互不推导**——
「公开可见」;「已公开,但无公开版本」(`visible=false` + `visibility=published`,刻意要让人
看出来的异常);「作品未公开」;「作品已下架」;「作品已删除」;「游戏行不存在」。
- 分页:每页 20(上限 50,由 api 客户端按服务端口径夹住),`nextCursor` 驱动「加载更多成员」;
页脚显示「成员行总数 N;已加载 M 条」(`totalMembers` 不受分页影响,不与 `members.length` 互相推导)。
- 增删成员后**重读第一页**而不是本地删行(游标基于排序,本地删会让后续翻页错位);
读取失败如实报错(如非法游标 400),不渲染成「还没有成员」。
测试(10 条,含新增/改写 4 条):草稿主题也能读到名单并逐条移除(移除后重读第一页)、
「已公开但无公开版本」与其它不可见原因分别展示、游标加载更多(末页按钮消失)、
读取失败如实报错不显示空名单。
|
||
|
|
d6d3913320 |
跟上主题详情契约变更:memberCount 为真实可见数 + rootsTruncated 截断信号
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/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 / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
- 客户端:GameDistributionThemeDetail 增加必填 rootsTruncated;getTheme 的响应类型与返回值透传该键(缺键按 false,空成员时服务端也是 false 而不是缺键) - 主题页:新增「共 N 棵作品树」,总数一律用 memberCount(真实可见成员数,不受 50 上限截断),不再用 roots.length;rootsTruncated 为 true 时给出明确提示「这里只显示前 A 个,共 B 个」,与族谱页的 truncated 同一约定 - 顺带确认:全仓没有别处按 memberCount === roots.length 做不变式(此前只有主题列表页展示 memberCount,主题页未展示计数) - 测试:新增一条——rootsTruncated=true 且 memberCount=120 / roots 只有 1 个时,截断提示出现且总数展示 120,不得出现用 roots.length 算出的「共 1 棵作品树」 |
||
|
|
0d0166c2d9 |
feat(游戏共创): 后台读取主题成员名单(含草稿/归档主题与不可见成员 + 可见性列)
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 / 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 Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
缺口:后台原先只能借**公开投影** `GET /api/game-distribution/themes/{themeId}` 列成员,而公开投影只服务
`published` 主题 ⇒ **草稿 / 已归档主题在后台看不到成员名单**,运营没法在发布前核对。
新增 `GET /admin/api/game-distribution/themes/{theme_id}/members?limit=&cursor=`:
- **鉴权照既有两层**:路由挂既有 admin 支的 `route_layer(require_admin_auth)`,handler 取
`Extension<AuthenticatedAdmin>`(未登录/失效 → 401 `UNAUTHORIZED`、非 admin → 403,同组同码同形);
模块侧 procedure 先跑 `require_editor_generation_runtime_service_identity`(照 `033e3aa79` 五条写接口)。
- **返回全部成员行,不套公开可见性过滤**,且**不要求主题已发布**(`draft` / `archived` 照常可读;
只有主题真的不存在才 404 `THEME_NOT_FOUND`)。响应:
`{ themeId, totalMembers, members: [{ rootGameId, title, sortOrder, createdAt, visible, visibility }], nextCursor }`。
- **两个可见性字段刻意独立**:
· `visible` = 「公开侧此刻会不会出现」,**复用** `game_distribution_theme_member_visible`(未删 + 已公开
+ 有当前公开版本),不另写第二套判定;
· `visibility` = 更细状态(新纯函数):游戏行不存在 → `missing`(优先于 `deleted`),软删除行 → `deleted`,
否则原样透传游戏行 `visibility`(`published` / `unpublished` / `suspended`)。
因此 `visibility == "published"` 但无当前公开版本时 `visible = false` ——运营能看出「公开了但没公开版本」;
三处钉住这个组合(纯函数单测、api-server payload 单测、事务结构断言)。
- **排序与分页照既有口径**:复用 `sort_theme_members`(`sort_order` 升序 + 成员 id 兜底)+ 新增
`page_admin_theme_members`;`limit` 缺省 20 / 上限 50 / `0` 取默认 / 超界截断(同一归一化);
游标 `"{sortOrder}:{memberId}"`,解析**只委托** `parse_game_distribution_theme_cursor` ⇒ 非法游标仍是
上一轮刚修好的**可达** `THEME_INVALID_CURSOR`(不另造一个不可达码);`totalMembers` 是成员**行**总数,
切页前算,不受分页影响。
- **契约与登记**:`packages/shared/src/contracts/gameDistribution.ts` 新增
`GameDistributionAdminThemeMemberRow` / `…ListResponse` / `…MemberVisibility`;parity 登记
`TS_ONLY_TYPES` +3、`RESPONSE_BUILDERS` +2(列表响应与单条成员各一条,条目形状有独立证据);api-server
用命名构建器(不内联 `json!`)。
- **测试**:module-game-distribution +5 条纯函数(`missing` 优先于 `deleted`、三类不可见各一条并断言
`visible`/`visibility` 组合、`published` 无公开版本 ⇒ `visible=false`、游标委托共享实现、翻页不重不漏、
末页 null、复用共享比较器与同一归一化);spacetime-module +1 并扩 2(结构断言:走主题索引、不套公开可见性
过滤、不复用「只取可见成员」的助手、不自写排序、不删行、`totalMembers` 在切页前取);spacetime-client +1
mapper(行总数与游标透传、两个可见性字段不互相推导、空名单是正常结果);api-server 例(401/403、草稿主题
可读、含不可见成员仍返回、`totalMembers` 不受分页影响、limit 缺省与截断、非法游标 → 400 `THEME_INVALID_CURSOR`、
主题不存在 → 404)。
- **文档**:技术方案 `§3.10.8`(新行 + `visible`/`visibility` 语义 + 「草稿也能读」的理由)与 `§3.4` 后台接口表;
里程碑(后台路由清单、实施清单、验收与测试清单,原「只能借公开投影」的留白项标记为已落地)。
- **生成绑定**:新增 4 个 `admin_theme_member_list*` / `list_admin_…_procedure` 生成文件 + `module_bindings.rs`
入口;wire format 有新增(新 procedure/结果类型)⇒ 部署需重新 publish 模块。
门禁:wasm build 0;`cargo check --all-targets` 0;`cargo test -p api-server game_distribution` **89 passed**;
`cargo test -p module-game-distribution` **106 passed**;`cargo test -p spacetime-module` **287 passed** / 1 ignored;
`cargo test -p spacetime-client` 39 passed;DTO parity 0(58 组 / **17** 构建器 / **15** 手拼类型);
`check:spacetime-schema` 0(96 tables);`check:encoding` 0(5424 files);`cargo fmt --all -- --check` 0;
`git diff --check` 0。
不在本提交内(属另一个 session 的文件,工作区里由我的子代理顺带做了**纯新增性**改动,未提交):
`apps/admin-web/src/api/adminGameThemeTypes.ts` 增加了三个指向共享契约新类型的别名 + 一段注释 —— 与该 session
「登记好之后改回引用共享契约」的计划一致,交由其 review / 提交(或直接删掉其本地重复定义)。
|
||
|
|
ce614d59c1 |
feat(游戏共创): 主题详情 rootsTruncated 信号(memberCount 报真实可见成员数)
Project CI / AI game creator shell Rust crates (pull_request) Successful in 6m1s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 7m10s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m58s
Project CI / Backend tests (pull_request) Successful in 9m10s
Project CI / Frontend tests (pull_request) Successful in 2m58s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m32s
Project CI / Native shell tests (pull_request) Successful in 6m37s
Project CI / Repository checks (pull_request) Successful in 4m55s
裁定(与族谱 `truncated` 同约定):`memberCount` = **真实可见成员数**(不受展示上限污染),新增布尔 `rootsTruncated`,**仅当 `roots` 被 50 上限截断时为 true**。此前两个数被同一个 50 上限截断 ⇒ 可见成员 > 50 时静默截断,客户端既看不到全部树、也拿不到任何信号。 - 纯函数:`game_distribution_theme_roots_truncated(visible_member_count, returned_root_count)` (相等 / 回传更多 ⇒ false;后者是防御性口径:两组数字不同源时不得凭空报「还有更多」)。 - 契约:`GameDistributionThemeDetail` 加 `roots_truncated`(serde camelCase ⇒ `rootsTruncated`), TS 镜像同步;parity `public_theme_detail_payload.mustEmit` 6 键 → **7 键**。 - 事务:`member_count` 走可见成员清单的 `len()`(**不再**经 `page_theme_members` 与上限),`roots` 仍是 同一清单排序后取前 50,`rootsTruncated` 由纯函数算出(不写死「>50 就 true」——阈值与上限是两个 独立事实);列表入口共用同一计数函数 ⇒ 同一主题在列表与详情里不会报出两个 `memberCount`。 - api-server:`public_theme_detail_payload` 增加 `rootsTruncated`;形状单测 6 → 7 键,并加 `memberCount=120 / roots=1 / rootsTruncated=true` 用例,证明两个键口径独立。 - 结构断言同步修正:列表侧原「成员数与 roots 共用同一上限」改为「成员数数的是全部可见成员(断言 源码里不含切页函数与上限常量)」;详情侧改为「必须调用共享纯函数 + 不得再恒等 `roots.len()` + 该字段必须进入返回值」。 - 生成绑定:`module_bindings/game_distribution_theme_detail_result_type.rs` 手改后用临时 out-dir 重跑 `spacetime generate --lang rust` 逐字节校对一致。**wire format 变更 ⇒ 部署需重新 publish 模块** (客户端绑定已同步)。 - 文档:技术方案 §3.4 / §3.10.6 / §3.10.9(原「已知限制·三个备选待拍板」→ 已定口径)、里程碑 (依赖、接口表、验收标准、纯函数表、测试清单、待确认项)、以及数据契约文档里那句「主题详情的 roots 与列表的 memberCount 永远一致」(本改动已使其为假)。 门禁:wasm build 0;`cargo check --all-targets` 0;`cargo test -p api-server game_distribution` 86 passed; `cargo test -p module-game-distribution` **101 passed**;`cargo test -p spacetime-module` 286 passed / 1 ignored;DTO parity 0(58 组 / **15** 构建器 / 12 手拼类型);`check:spacetime-schema` 0(96 tables); `check:encoding` 0(5420 files);`cargo fmt --all -- --check` 0;`git diff --check` 0。 遗留(不在本仓可改范围,需前端 session 跟进):`src/services/gameDistributionClient.ts` 有自己一份主题 详情本地类型与 normalize,会丢弃 `rootsTruncated`(约 3 行小改),因此网页主题页暂时拿不到截断信号; admin-web 走共享契约类型,后台侧即时生效。 |
||
|
|
4a33397822 |
chore(游戏共创): 主题注释失真修正 + 后台主题 payload 纳入契约门禁
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m53s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m48s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m42s
Project CI / Backend tests (pull_request) Successful in 9m47s
Project CI / Frontend tests (pull_request) Successful in 4m4s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m56s
Project CI / Native shell tests (pull_request) Successful in 7m55s
Project CI / Repository checks (pull_request) Successful in 6m8s
1) 注释失真(独立复核 §B8):`module-game-distribution/src/theme.rs` 与 `spacetime-module/src/game_distribution.rs` 原先声称「api-server 与事务都调 `game_distribution_theme_text_violation`」,但全仓只有写入事务一处调用(HTTP 层没有预校验)。 选择**改注释**(单一判据来源就是事务),不给 HTTP 层再叠一层同名校验——否则「HTTP 挡住的」 与「落库挡住的」会重新长出两套判据。两处注释都改成明确写「只有事务调用 + api-server 不做预校验」。 2) 后台主题 payload 的契约门禁:`admin_theme_payload` / `admin_themes_payload` / `admin_theme_mutation_payload` / `admin_theme_member_payload` 原先既无 TS 类型也未登记 parity, 形状只有 api-server 单测钉着 → 后台 UI 落地时容易与实现漂移。 - `packages/shared/src/contracts/gameDistribution.ts` 新增 5 个 TS 类型 (`GameDistributionAdminTheme`、`…ListResponse`、`…MutationResponse`、`…MemberResponse`、 `…MemberRemovalResponse`),注释里写清两处刻意差异:后台主题条目比公开摘要多出 `sortOrder`/`status`/时间戳,且 `memberCount` 是**成员行总数**(含当前不可见成员), 公开投影里同名键是**当前可见**成员数;后台列表**没有** `nextCursor`。 - `api-server`:把 handler 里内联的成员移除响应抽成命名构建器 `admin_theme_member_removal_payload`——内联 `json!` 不在 parity 的证据范围内,抽出来这条 形状的漂移才会被门禁抓住。 - parity 登记:`TS_ONLY_TYPES` +5(这些形状服务端同样是逐字段手拼 JSON,没有 Rust 结构体可对, 要收口得先把响应改成结构化类型),`RESPONSE_BUILDERS` +5(响应键与 TS 字段逐键比对)。 门禁:`cargo test -p api-server game_distribution` 86 passed;`cargo test -p spacetime-module` 286 passed / 1 ignored;DTO parity 0(58 组类型 / **15** 个构建器 / **12** 个手拼类型); `check:encoding` 0(5420 files);`cargo fmt --all -- --check` 0;`git diff --check` 0。 |
||
|
|
e401963d3a |
fix(游戏共创): 非法游标回归稳定码 THEME_INVALID_CURSOR(契约码此前在 HTTP 面不可达)
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (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
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
端到端实测(54 项里唯一红的那条):`GET /api/game-distribution/themes?cursor=abc` 回 400,但
`error.code = "BAD_REQUEST"`——技术方案 §3.4 与主题 e2e 脚本承诺的稳定码 `THEME_INVALID_CURSOR`
在 HTTP 面上拿不到,客户端只能去匹配中文文案。
根因:`map_spacetime_error` 的 `THEME_` 分支前置条件是「消息含 `THEME_`」,而模块侧游标解析只回
中文串「主题列表游标格式无效」⇒ 落兜底分支成 400 + 通用 `BAD_REQUEST`;契约常量与那条映射分支
因此是死代码。且 api-server 原有单测**明确要求**文案不含 `THEME_`(口径留了两套)。
口径二选一,选**让码可达**(模块产出前缀),删掉「要求不含 `THEME_`」的断言:
- `module-game-distribution/src/errors.rs`:新增 6 个主题码常量
`GAME_DISTRIBUTION_THEME_{NOT_FOUND,BAD_REQUEST,INVALID_CURSOR,IDEMPOTENCY_CONFLICT,MEMBER_NOT_ROOT,MEMBER_GAME_NOT_FOUND}_CODE`,
并把 `Display` 从字面量改为**复用同一批常量**(消灭「常量改了、`Display` 没改」这类只有真栈才发现的漂移)。
- `theme.rs`:`parse_game_distribution_theme_cursor` 产出 `THEME_INVALID_CURSOR: 主题列表游标格式无效`;
文档注释更新为「只保留 `FORK_` 这个排在 `THEME_` 分支之前的子串禁忌」(其余子串已抢不到)。
- `lib.rs`:导出新增的 6 个码常量。
- 测试:
· `domain.rs::theme_errors_are_prefixed_with_their_machine_code` 改为**枚举全部 6 个主题码**(含唯一
不走领域变体的游标路径——正是当初漏掉它的原因),并加「任何新增码都必须进这张表」的覆盖完整性断言;
· `theme.rs::invalid_cursor_message_stays_in_the_bad_request_bucket` 增加「必须以稳定码开头」;
· api-server 新增 `theme_error_codes_are_reachable_from_module_messages`:用**模块真实产出的消息**
逐码断言 `(状态码, 稳定码)` 可达,并比对模块常量与 `shared-contracts` 常量是同一组字符串;
· api-server `theme_list_invalid_cursor_maps_to_bad_request` 改为断言映射出 `THEME_INVALID_CURSOR`,
只把 `FORK_` 留在禁忌列表里(并写明理由)。
门禁:`cargo test -p module-game-distribution` **100 passed**;`cargo test -p api-server game_distribution`
**86 passed**;`cargo check --all-targets` 0;DTO parity 58 组 / 10 构建器;`check:encoding` 0;
`cargo fmt --all -- --check` 0;`git diff --check` 0。
|
||
|
|
909f3d5fa2 |
网页端共创主题:共创 Tab + 主题页(逐根内嵌作品树)+ 详情页主题入口 + 网关清单
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/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 / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
- 客户端:新增 listThemes(游标分页,读 nextCursor)与 getTheme(404 由页面渲染成降级态);getGame 的返回类型增量 themes(匿名也返回;无主题时是空数组而不是缺键) - 共创 Tab:广场页新增「游戏 / 共创」页签,复用既有 game-category-tabs 结构与类名,切到 /games/themes - 主题列表页 GameThemesPage:卡片展示 name / summary / badge / memberCount;只有 nextCursor 非空才渲染「加载更多」并在点击时追加;空态与失败重试照既有写法 - 主题页 GameThemePage:标题 / 简介 / 角标 + 成员根清单;**逐根内嵌渲染作品树**——直接复用族谱页(GameLineagePage 新增 embedded 变体,只隐藏页面外壳:返回按钮 / 页头 / 脚注),树查询、可见性过滤、稳定排序与截断全部走 M3 那一份实现,不新建第二套树查询或树渲染(每根一次 /lineage 的 N+1 是技术方案 §3.10.4 已接受的取舍);已发布但可见成员为空 → 明确空态而不是错误;主题不存在 / 未发布 → 错误态 - 详情页:共创信息卡渲染所属主题角标(点击进主题页),第 N 代作品同样可见(服务端按根反查);无主题时不渲染空容器 - 路由登记:新增 /games/themes 与 /games/theme(详情用 ?id=),四处同批登记(STAGE_ROUTE_ENTRIES + SelectionStage 类型 + 壳层 lazy/回调/渲染分支 + 页面标题),并同步三份 nginx SPA allowlist 与 Pingora MAIN_SPA_PATHS:check:nginx-spa-routes(20 SPA routes / 3 模板)与 check:pingora-route-parity 均绿 - 测试:主题列表三例(渲染与卡片跳转 / 有游标时的加载更多与追加 / 空态与失败重试)、主题页三例(逐根两棵树且复用 lineage 查询 + 全屏入口参数 / 空成员空态 / 404 错误态)、详情页主题入口两例(渲染并可跳转 / 无主题不渲染容器)、路由与标题登记断言、壳层三例(页签切换 / 列表进主题页 / 主题页按 ?id= 渲染并复用族谱查询) |
||
|
|
58da0e67db |
test(游戏共创): 新增共创主题端到端验收脚本
Project CI / AI game creator shell Rust lane 1/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
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
- 新增 scripts/check-game-distribution-theme-e2e.mjs(约 1160 行):真库验收公开读 + 后台写 +
作品详情 themes 增量,复用 lineage 脚本的完整发布链路 helper(脚本头注释逐条标注出处),
覆盖 9 组共 54 条断言:
· 建主题→加根成员→公开读:公开列表只含 published(且不含 status 字段)、详情 roots 逐条与公开
目录同一投影(键集合 23=23)、memberCount 与 roots 长度一致
· 只允许根:第 1 代子作品当成员 → 409 THEME_MEMBER_NOT_ROOT;不存在的 gameId → 404 THEME_MEMBER_GAME_NOT_FOUND
· 跨主题多归属:同一个根加入两个主题,两条主题都能读到它,作品详情 themes 长度=2
· 作品详情 themes 口径:匿名与登录都发;**专门构造第 1 代衍生作品**(带 fork 声明 + 完整发布链路)
并断言它也返回根所属的两个主题(先取根再反查);无归属作品返回空数组
· 可见性:draft 主题公开 404(后台按 draft 过滤仍可见)、archived 公开 404 且作品详情 themes 同步消失、
改回 published 恢复;已发布但成员全不可见 → 200 + 空 roots + memberCount=0;
成员下架 → 从 roots 消失,重新公开(新版本审核通过)→ 同一行自动回到 roots 且仍只一行
· 分页:默认 20、limit=999 截断到 50、limit=20 游标翻页 3 页 54 条不重不漏、末页 nextCursor=null、
?cursor=abc → **400**(状态码符合契约)
· 后台权限:五条路由未登录 401;普通作者 token 403;成员 PUT/DELETE 免幂等键、重复 PUT 只留一行
且 createdAt 不变、DELETE 幂等(data 载荷逐字段相同,信封 meta.requestId 每请求不同属既有协议)
· 后台幂等:同键重放 replayed=true 且不产生第二个主题、同键换请求 409 THEME_IDEMPOTENCY_CONFLICT、
缺 Idempotency-Key → 400
· 三条公开路由匿名 200 且带 Cache-Control: no-store
- **实测 53 PASS / 1 FAIL**:唯一失败是已确认的产品缺口(仅报告、未改后端)——非法游标的状态码是
400 ✓,但稳定码 THEME_INVALID_CURSOR 不可达:api-server/...:5343-5346 为该码注册了 400 映射,
而模块侧只回纯文案「主题列表游标格式无效」(module-game-distribution/src/theme.rs:205-215),
不含分支前置所需的 `THEME_` 前缀,客户端实际拿到 code=BAD_REQUEST。脚本刻意保留这条红断言
(契约真值),并附 NOTE 说明成因与证据。
- package.json:新增 npm script check:game-distribution-theme-e2e
|
||
|
|
09a1cf5497 |
docs(游戏共创): 共创主题文档回填(§3.4 接口表 / §3.10 实现状态 / 里程碑 Status 与验收)
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m57s
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
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 / Native shell tests (pull_request) Has been cancelled
服务端三块(`2fa201e0d` 模型与纯函数、`742723a58` 公开读、`033e3aa79` 后台写)已落地,本次把文档从「只落设计」补齐到「服务端已实现」,并写死一条已知限制。
- **技术方案 `§3.4`**:新增 5 条接口行(真实路由/鉴权/错误码/字段名均以 `git show` 核对代码为准,非猜测)——公开 `GET /api/game-distribution/themes`(匿名 + `no-store`;只含 `published`;limit 缺省 20 / 上限 50 / 超界截断;游标 `"{createdAtMicros}:{themeId}"`;非法游标 400;末页 `nextCursor: null`;`memberCount` = 公开可见成员数)、`GET /api/game-distribution/themes/{themeId}`(顶层扁平 `{themeId,name,summary,badge,memberCount,roots}`;`roots` 复用公开目录同一份投影;不存在/draft/archived → 404 不返回空壳;已发布空成员 → 200 + 空 `roots`),以及 `GET /games/{gameId}` 的 `themes` 增量(匿名与登录都发、空数组恒发;先取根再按根反查 ⇒ 第 N 代作品也能跳主题页);后台 5 条(`require_admin_auth` + `AuthenticatedAdmin`,未登录/失效 401 `UNAUTHORIZED`、非 admin 403;创建与编辑要求 `Idempotency-Key`,同键重放 `replayed: true`、同键换请求 409 `THEME_IDEMPOTENCY_CONFLICT`;成员增删**不要求**幂等键(确定性主键天然幂等,删不存在也 200);非根成员 409 `THEME_MEMBER_NOT_ROOT`;后台列表含 draft/archived、limit 缺省与上限 200、无游标;`theme_id` 服务端生成 `theme-{uuid}`)。
- **`§3.10`**:各小节「本轮实现 / 留白」标注更新为现状(服务端已实现;公开前端与后台 UI 仍留白);`§3.10.6`/`§3.10.9` 明确写下**已知限制**——主题详情 `roots` 沿用页上限 **50** 且 `memberCount == roots.len()`,可见成员 > 50 时会**静默截断且没有「还有更多」标志**,三个备选(去上限 / 给成员加游标 / `memberCount` 报真实可见数)待拍板,本轮不改契约。
- **`§7`**:第 3 条(共创主题)改为「设计已采纳 + 服务端已实现」,仍待拍板收敛为两条:① 主题级排序口径(公开列表当前按 `created_at` 倒序 + `themeId` 兜底;若要按运营 `sort_order` 展示需改游标格式并同步前端);② 上述 `roots` 50 上限行为。
- **里程碑文件**:`Status` 由 `proposed` → 「服务端已实现(附四个提交号);公开前端与后台管理 UI 待做」,Version 1.0 → 1.1,新增「已落地提交」行;实施清单 A–F 标注已落地提交、G 标未做(待前端)、H 分「已落地层 / 未做层」、I 补执行状态;**验收标准勾 17/19**(第 17 条公开前端、第 18 条 SPA 路由门禁留空并注「等前端」);文末写明「dev 栈端到端整链未跑(`scripts/check-game-distribution-theme-e2e.mjs` 未创建),依赖真实库存的运行时分支目前只到单元/结构/映射层」。
- **数据契约文档**:两张主题表小节的「写入路径属后续里程碑」改为现状(读/写 procedure 与事务名),表结构描述未动。
- **门禁**:`check:doc-index` 0(252 份 Markdown,current=121 / historical=15 / review=1);`check:encoding` 0(5414 files);`git diff --check` 0。
- **环境限制(标注,非绿)**:`check:generated-bindings` 本机 `EXIT=1`,原因是 `apps/ai-game-creator-shell/src-tauri/build.rs:167` 校验随包资源时缺 `bin/win-x64/agc_godot_editor.dll`(需先跑随包资源准备步骤)——纯环境前置,与本次只改 `docs/**` 无关;该检查的 AGC 段本地从来跑不了(CI 绿)。
|
||
|
|
033e3aa79a |
feat(游戏共创): 共创主题(三)后台写路径(5 条 admin 路由 + 事务 + 幂等)
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m59s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m47s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m43s
Project CI / Backend tests (pull_request) Successful in 9m27s
Project CI / Frontend tests (pull_request) Successful in 3m13s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m24s
Project CI / Repository checks (pull_request) Successful in 5m4s
Project CI / Native shell tests (pull_request) Successful in 6m50s
按 §3.10.8:后台 UI 不在本轮,本轮只落**接口与事务**。
- **鉴权(照仓库既有 admin 体系,不自造)**:5 条路由挂在既有 `/admin/api/game-distribution/*` 支,统一 `route_layer(require_admin_auth)`,handler 取 `Extension<AuthenticatedAdmin>`;未带 / 失效会话 → **401 `UNAUTHORIZED`**(与同组 games/reviews 路由同码同形),非 admin role → 403。模块侧第二层:写 procedure 与后台列表都要求受信服务身份(`require_editor_generation_runtime_service_identity`),只有 api-server 能调。
- **5 条路由**:`POST /themes`(创建;服务端生成 `theme-{uuid}`;要求 `Idempotency-Key`,摘要只覆盖客户端可见请求体,**不含重试时重新生成的 `theme_id`**)、`PUT /themes/{theme_id}`(整体覆盖 name/summary/badge/sortOrder/status,生效即刷新 `updated_at`,重放不写库不刷新)、`PUT /themes/{theme_id}/members/{root_game_id}`(**不要求幂等键**——确定性主键天然幂等;可带 `sortOrder`)、`DELETE …/members/{root_game_id}`(不要求幂等键;成员不存在也算 200,响应刻意不含「之前存不存在」→ 重复调用逐字节相同)、`GET /themes?limit=&status=`(**含 draft/archived**,status 白名单 `all|draft|published|archived`,limit 缺省与上限 200、超界截断、无游标)。
- **成员只允许根作品**:用 `game_distribution_theme_root_acceptable(has_lineage_row)`,非根 → **409 `THEME_MEMBER_NOT_ROOT`**;作品不存在 → 404 `THEME_MEMBER_GAME_NOT_FOUND`;主题不存在 → 404 `THEME_NOT_FOUND`。**不做「成员必须已公开」的前置校验**(运营可先挂草稿根,作品公开后自动出现在公开投影里);归档主题**不清理**成员行(与公开投影「跳过不删行」同一口径)。
- **领域错误码**:`module-game-distribution/src/errors.rs` 新增 5 个带码错误(`ThemeNotFound` / `ThemeBadRequest{reason}` / `ThemeIdempotencyConflict` / `ThemeMemberNotRoot{game_id}` / `ThemeMemberGameNotFound{game_id}`),Display 一律 `CODE: 文案`,并由测试钉住「码后必须跟冒号」;api-server 集中映射,不落 axum 默认 422 纯文本。
- **纯函数补充**:后台 status 过滤器白名单(`all` + 三态的单一实现)、文本上限常量(名称 40 / 简介 200 / 角标 16,按 UI 一行与卡片摘要的量级取,写进注释)与 `game_distribution_theme_text_violation`(trim 后判空名与超长,返回可拼进 `THEME_BAD_REQUEST:` 的原因)。
- **测试**:`theme.rs` +2 纯函数(status 过滤器白名单、文本违规判定)、`domain.rs` +1(错误码前缀)、spacetime-module +8 事务结构断言、client mapper +3、api-server +6(401 同码同形、创建/编辑/成员增删的形状与错误码、后台列表含 draft、重复 PUT 幂等、非根成员被拒)→ `cargo test -p api-server game_distribution` **85 passed**、`module-game-distribution` **100 passed**、`spacetime-module` **286 passed**、`spacetime-client` 37 passed。
- **门禁**:wasm build 0;`cargo check --all-targets` 0;`cargo test -p api-server game_distribution` 85 passed;`cargo test -p module-game-distribution` 100 passed;`cargo test -p spacetime-module` 286 passed / 1 ignored;`cargo test -p spacetime-client` 37 passed;DTO parity 58 组 / 10 构建器;`check:spacetime-schema` 0(96 tables);`check:encoding` 0(5414 files);`cargo fmt --all -- --check` 0;`git diff --check` 0。
- 生成绑定:新增 15 个 `module_bindings/*theme*/admin_theme*` 文件 + 入口声明(无重排);其余 202 个文件的 rustfmt 漂移按上一轮做法逐字节还原,未跑任何 git 写命令。
|
||
|
|
742723a58c |
feat(游戏共创): 共创主题(二)公开读路径(事务 + client + 两个公开路由 + 详情 themes 增量)
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m44s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m35s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m37s
Project CI / Backend tests (pull_request) Successful in 9m29s
Project CI / Frontend tests (pull_request) Successful in 3m7s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m7s
Project CI / Repository checks (pull_request) Successful in 6m48s
Project CI / Native shell tests (pull_request) Successful in 8m39s
- **事务**(`spacetime-module`):公共列表 `list_game_distribution_themes_tx`(匿名可读;先按 `published` 过滤、再排序切页——`created_at` 倒序 + `theme_id` 兜底;只对当页现算 `member_count`;不写库);主题详情 `get_game_distribution_theme_detail_tx`(不存在 / 未发布**同一句**「主题不存在」→ 404;`roots` 逐条复用公开目录同一份 `public_game_distribution_snapshot`;成员可见性委托 `game_distribution_theme_member_visible`,被滤掉的行**不删除**;已发布但可见成员为空 = Ok + 空 roots = 200);作品→主题 `list_game_distribution_theme_refs_for_root_tx`(入参任意代作品,先取**根**再按根反查成员、只保留 `published` 主题;排序复用 `sort_public_themes`)。**根解析只有一份实现**:抽成 `game_distribution_theme_root_of` 并让既有 `game_distribution_lineage_tx` 复用(测试钉住)。
- **client**:3 个新方法 + mapper 记录类型(`spacetime-client`)。
- **公开路由**(`api-server`):`GET /api/game-distribution/themes?limit=&cursor=`(匿名可读 + `no-store`;`limit` 缺省 20 / 上限 50 / 超界截断;非法游标 **400** 透传;末页 `nextCursor: null`)、`GET /api/game-distribution/themes/{theme_id}`(顶层扁平 `{themeId,name,summary,badge,memberCount,roots}`;不存在 / draft / archived → **404**,不回空壳、不带 `THEME_` 码)、既有公开作品详情追加 `themes`(匿名与登录**都**发、空数组恒发;`collected` 仅登录发的老口径不变;因按根反查,**第 N 代作品也能跳到主题页**)。
- **错误码**:新增 6 个 `THEME_*` 稳定码集中在 `map_spacetime_error` 映射(不落 axum 默认 422 纯文本);未登记码兜底 **400 `THEME_ERROR`**。
- **契约/parity**:5 条手拼响应构建器登记(`public_themes_payload` / `public_theme_detail_payload` / `public_theme_summary_payload` / `theme_reference_payload`,并给 `public_game_detail_payload` 加 `mustEmit: [themes]`)→ 58 组类型 + 10 个构建器一致。
- **测试 +13**:spacetime-module 4 条源码结构断言(根解析单一实现、先过滤再切页、投影不删行、详情只有两种失败且同一 404 文案、refs 走具名根索引 + 只保留 published)、api-server 7 条(路由挂载与 `no-store`、列表/详情响应形状与末页 null、`roots` 逐字节等于 `public_game_payload`、limit 缺省与截断、非法游标 400、404 与 6 个 THEME_ 码映射、作品详情 `themes` 恒发而 `collected` 仅登录)、client mapper 2 条。
- **门禁**:wasm build 0;`cargo check --all-targets` 0;`cargo test -p api-server game_distribution` **79 passed**;`cargo test -p module-game-distribution` **97 passed**;`cargo test -p spacetime-module` **278 passed** / 1 ignored;`cargo test -p spacetime-client` 34 passed;DTO parity **58 组 / 10 构建器**;`check:spacetime-schema` 0(96 tables);`check:encoding` 0(5399 files);`cargo fmt --all -- --check` 0;`git diff --check` 0。
已知限制(**已上报,待拍板**):主题详情的 `roots` 沿用页上限 50,`memberCount == roots.len()`,因此可见成员 > 50 时**静默截断且无「还有更多」标志**——设计文档未定义该行为,三个备选(去上限 / 加成员游标 / memberCount 报真实数)待定;本轮不改契约。
|
||
|
|
2fa201e0dc |
feat(游戏共创): 共创主题(一)数据模型与领域纯函数
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m30s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m12s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m44s
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
按 `docs/【技术方案】游戏共创与作品Fork-2026-10-03.md §3.10` 与里程碑《共创主题与作品树-2026-10-06》的清单 A/B/F 落地(本块**不含** procedure / 路由)。
- **表**:`game_distribution_theme`(`theme_id` 主键、`name`/`summary`/`badge`/`sort_order`/`status ∈ draft|published|archived`/`created_by_user_id`/`created_at`/`updated_at`)+ `game_distribution_theme_member`(确定性主键 `member_id = "{theme_id}:{root_game_id}"`,`theme_id`、`root_game_id` 各具名 btree 索引,`sort_order`、`created_at`);归档 / 下架只改公开投影,不删成员行。`migration.rs` 白名单登记两张表(随迁移导出/导入)。
- **生成绑定**:4 个 `game_distribution_theme*` 生成文件 + `module_bindings.rs` 入口(纯追加)。生成时**不覆盖工作树**(本仓共享工作树禁止 git 写命令):先 `spacetime generate --lang rust --out-dir <仓外临时目录>`,rustfmt 后只拷回本次相关文件,避免上一轮踩过的「rustfmt 漂移把别人文件一起改」。
- **领域纯函数**(`module-game-distribution/src/theme.rs`,风格照同目录 `collection.rs`):状态合法/公开可见判定、`game_distribution_theme_member_id`、成员可见性(**委托** `collection.rs` 的判定,不复制第二套)、`game_distribution_theme_root_acceptable(has_lineage_row)`、页大小(缺省 20 / 上限 50 / 0 取默认 / 超界截断)、游标编解码(`"{createdAtMicros}:{themeId}"`,Err 文案「主题列表游标格式无效」,已核对不含 404/409 关键词)、`sort_public_themes`(`created_at` 倒序 + `theme_id` 兜底)、`page_public_themes`(排序 → retain 游标之后 → 多取一条判 has_more;**先过滤再切页**的顺序语义写进文档注释)、`sort_theme_members`(`sort_order` 升序 + `member_id` 兜底)与 `page_theme_members`。
- **契约**:`shared-contracts` 新增 `GameDistributionThemeStatus` / `GameDistributionThemeReference` / `GameDistributionThemeSummary` / `GameDistributionThemeListResponse` / `GameDistributionThemeDetail` / `GameDistributionCreateThemeRequest` / `GameDistributionUpdateThemeRequest` / `GameDistributionUpsertThemeMemberRequest`,`GameDistributionGameSummary` 追加可选 `themes`(按 `collected` 先例只在详情路径下发);TS 镜像同步;parity 登记 **58 组**(响应构建器待路由落地后再登记,parity 要求函数真实存在)。
- **数据契约表目录**:补两张表小节,94 → **96**。
- **测试**:`theme.rs` 16 个单测(成员 id 确定性、状态三态与公开可见、成员可见性逐格与收藏判定等价、根判定、页大小边界、游标往返与非法输入、排序稳定性与同 `sort_order` 兜底、分页不重不漏)。
- **门禁**:wasm build 0;`cargo check --all-targets` 0;`cargo test -p module-game-distribution` **97 passed**;`cargo test -p spacetime-module` 274 passed / 1 ignored;DTO parity **58 组**;`check:spacetime-schema` 0(**96** tables);`check:server-rs-ddd` 0;`check:encoding` 0(5388 files);`cargo fmt --all -- --check` 0;`git diff --check` 0(8 个改动文件 0 删除行)。
|
||
|
|
063c04a1b3 |
docs(游戏共创): 共创主题设计定稿(§3.10 + 里程碑《共创主题与作品树-2026-10-06》)
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
需求形态(飞书):共创 Tab 下有多个「共创主题」,点进去是一棵(或一组)作品树;**主题由平台/运营命名,不由根作品决定**;作品在游戏 Tab 里仍作为独立作品展示,详情页有 Fork 入口并能看到 / 跳到对应主题页。本轮只落设计(不写业务代码),实施清单见里程碑文件。
设计要点与理由(详见 §3.10):
- 实体:`game_distribution_theme`(`theme_id` 主键、三态 `draft|published|archived`、`sort_order`、`badge`、`created_by_user_id`)+ `game_distribution_theme_member`(确定性 `member_id = "{theme_id}:{root_game_id}"`,`theme_id` / `root_game_id` 各具名 btree 索引)。
- **成员只允许根作品**:树查询 `/games/{id}/lineage` 按根聚合,否则同一棵树会在主题页里出现多次(去重/高亮打架);代价=要挂就挂它所属的根。跳到某一代节点属 UI 层(族谱页已有 `from` 高亮)。
- **允许跨主题多归属**:主题是运营叙事,「平台精选」「双人合作」会同时收录同一个根;确定性主键只保证**同一主题内**不重复。代价=作品详情要返回多值、运营需知悉。
- **树直接复用 `/games/{id}/lineage`**,主题侧**不重建**任何树查询/树整形(没有第二套可见性/排序可漂移);主题详情只返回成员根清单(N+1 本轮接受,批量树端点留白)。
- 可见性:公开侧只见 `published` 主题;成员只出现公开未删且有当前公开版本的根(**投影跳过但不删行**,重新公开自动回来);主题不存在/未发布 → **404**;已发布但可见成员为空 → **200 + 空成员列表**。
- 公开三接口:`GET /themes`(游标分页沿用默认 20/上限 50/非法 400/末页 null)、`GET /themes/{theme_id}`(+ `roots`)、作品详情 `themes` 增量(**先取该作品的根、再按根反查**,因此第 N 代作品也能跳到主题页)。
- 后台五接口(创建/编辑/增删成员/后台列表,均幂等),鉴权**复用既有 `require_admin_auth` + `AuthenticatedAdmin`**,不自造;后台 UI 不在本轮。
- 留白 5 项(各写不做理由与将来接法):主题封面图、slug/URL 别名、埋点统计、跳到某一代的高亮、批量树端点。
- 同步收敛:§6 里程碑表 M4 行指向新里程碑;§7 第 3 条「共创主题」从**待拍板**改为**已拍板采纳**,并把「主题级排序口径」留作唯一待产品确认项。
门禁:`check:doc-index` 0(252 份 md;新里程碑在 `plans/` 下免分类);`check:encoding` 0(5383 files);`git diff --check` 0。
注:§3.10 的前约 200 行因共享工作树/索引,被上一提交 `f703bc49d`(注释修正)一并带上;本提交补齐其余章节 + 里程碑文件。
|
||
|
|
f703bc49d4 |
docs(游戏共创): 修正收藏幂等注释与实现不符之处(换用户不是 409)
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
端到端实测(`scripts/check-game-distribution-collection-e2e.mjs`)发现注释与实现不一致,**行为本身无缺陷,改的是注释**: - `api-server/src/modules/game_distribution.rs:1389-1396`(`collection_request_digest` 文档注释):原写「同一个 key 撞到不同作品 / 不同用户」都被判成同键不同请求(409)。实际只有**换作品**是 409;**换用户**不会命中彼此收据(收据键 `(user_id, action, idempotency_key)` 本身含 `user_id`),两个用户各走各自的新请求、正常 200。已改写为「换作品 → 409;换用户 → 200 各自成功」,并注明这条注释曾写错。 - `api-server/src/modules/game_distribution.rs:1404-1408`(`collect_game` handler 幂等说明):同上(原文「同键不同请求(换作品 / 换用户)是 409」)。 - `api-server/src/modules/game_distribution.rs:7896-7897`(测试 `collection_request_digest_binds_user_and_game` 的描述):补上「换作品 → 409 / 换用户不会(收据按用户隔离)」;**断言未改**(它只断言摘要对两维度敏感,本来就与实现一致)。 - `docs/【技术方案】游戏共创与作品Fork-2026-10-03.md:339`(`§3.4` 接口表同一句话):同一口径修正。 - `module-game-distribution/src/collection.rs:173`:把易被误读为「客户端 Idempotency-Key」的注释改为明确的「主键派生必须对两个维度都敏感」,并说明与幂等收据的键无关。 `spacetime-module/src/game_distribution.rs:4717-4719` 的注释本来就与实测一致(「不同用户 / 不同作品即使共用同一个 Idempotency-Key 也不会互相命中」),未改。 门禁:`cargo check -p api-server --all-targets` 0(仅既有 1 warning);`cargo test -p api-server collection` 7 passed;`cargo fmt --all -- --check` 0;`check:encoding` 0(5382 files);`git diff --check` 0。 遗留(非本人文件,未改):`scripts/check-game-distribution-collection-e2e.mjs:32-34,537` 的说明文字仍在描述「api-server 注释与实测不一致」,现已一致,需该脚本作者同步(归另一会话)。 |
||
|
|
f09607d903 |
feat(游戏共创): 收录(收藏)列表补真分页(cursor + limit)
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
- 纯函数(`module-game-distribution/src/collection.rs`,与收藏另两条规则同文件):`encode/parse_game_distribution_collection_cursor`(`"{created_at_micros}:{collection_id}"`,复用仓库既有 `"{micros}:{id}"` 惯例;非法 → Err「收藏列表游标格式无效」→ 400)、`game_distribution_collection_page_limit`(0/缺省 → 20,超界 → 50)、`game_distribution_collection_page`(稳定全序排序 → 跳过游标之前 → 取 limit → 多取一条判 has_more,只对页内最后一条编码下一游标)
- 排序与顺序语义:`created_at` 倒序 + `collection_id` 升序兜底(主键、同用户内唯一 ⇒ 全序,翻页不重不漏);**先按可见性过滤、再排序切页**——游标位置必须落在已过滤序列上,否则被过滤的行会让下一页漏项(推理写进 tx 与纯函数注释);snapshot 只对最终页成员计算
- 模块:list 的 input 增 `limit` / `cursor`,result 增 `next_cursor`;api-server `my-collections` 加 `Query<MyCollectionsQuery>`,默认 20 / 上限 50(网格一屏 vs 单响应体积;与后台列表的 200 口径不必相等,理由写进注释),超界**截断**不报错,非法游标 400 透传不吞,日志带 `has_more`
- 契约:Rust DTO 增 `next_cursor`、TS 镜像同步、parity 登记(50 组一致)
- 文档:§3.4 的 `my-collections` 行补分页语义(默认/上限/游标格式/非法 400/末页 null/排序口径)
- 测试 13 条:纯函数 8(不足一页 → None;恰好整页不产生空游标;5 条 limit=2 连翻 3 页不重不漏;同 `created_at` 用 `collection_id` 兜底;limit=0 与超界;游标往返 + 7 种非法输入)、模块事务结构 2、api-server 3(默认与截断、`nextCursor` 透传、非法游标 → 400)
- 门禁:wasm build 0;`cargo check --all-targets` 0;`cargo test -p module-game-distribution` **81 passed**;`cargo test -p api-server game_distribution` **73 passed**;`cargo test -p spacetime-module` 274 passed / 1 ignored;DTO parity **50 组**;`check:spacetime-schema` 0(94 tables);`check:encoding` 0(5382 files);`cargo fmt --all -- --check` 0;`git diff --check` 0
|
||
|
|
eb7349ef3d |
test(游戏共创): 新增收藏(收录)端到端验收脚本
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
- 新增 scripts/check-game-distribution-collection-e2e.mjs(约 750 行):真实 HTTP 验收收藏链路,
复用 lineage 脚本的发布链路 helper(脚本头注释逐条标注出处),覆盖 9 组共 46 条断言:
· 幂等与「只一行」:两次不同键都成功(replayed=false);同键重放 replayed=true;两种情况都断言
my-collections 长度=1 且该作品只出现一次(无收藏计数接口,按工单允许的列表去重与长度证明)
· 同键不同请求:换作品 → 409(「幂等键对应的请求摘要不一致」);**换用户 → 200 新收藏**,与
api-server handler 注释「换用户也是 409」不一致(收据键含 user_id,模块侧注释与实测一致),
脚本按实测断言并在 NOTE 与报告里标注
· DELETE 幂等:已收藏 / 未收藏 / 从未收藏且未公开 三种情形都 200 {collected:false} 且不发 replayed
· 鉴权与缓存:三条路由未登录都 401 且带 Cache-Control: no-store(证明挂载而非 404/405);
已登录但缺 Idempotency-Key 的 PUT → 400
· 状态门:草稿 PUT → 409「作品状态不允许收藏(未公开或已软删除)」(含「状态」不含「不存在」,
不泄露未公开作品存在性);不存在的 gameId → 404「作品不存在」
· 下架 → 重新公开:收藏后下架读侧过滤掉该作品,重新公开(新版本审核通过)后又回到列表且仍只一行
(证明下架不删行、只在读侧过滤)
· 公开详情 collected:匿名 23 键无 collected;已登录 24 键恰好多 collected=true;
去掉该键后与匿名逐字段一致;公开目录同作品条目与匿名详情键集合与取值完全一致
· 跨用户隔离:A 收藏后 B 的列表不含该作品、B 的 collected=false
- package.json:新增 npm script check:game-distribution-collection-e2e
- 实测:本地 dev 栈(SpacetimeDB 3110 / api-server 8188)46 项 46 PASS / 0 FAIL / 0 SKIP
|
||
|
|
785152f70b |
网页端收藏:作品详情页收藏切换 + 我的收藏页签
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m50s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m38s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m38s
Project CI / Frontend tests (pull_request) Failing after 1m10s
Project CI / Backend tests (pull_request) Successful in 9m34s
Project CI / AI game creator shell web tests (pull_request) Successful in 4m3s
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
- 客户端:新增 setGameCollection(PUT 带 Idempotency-Key;DELETE 不带)与 listMyCollections({games,nextCursor},条目形状与公开目录逐字一致,可复用同一套卡片);getGame 返回类型放宽为 GameDistributionGameWithCollection,collected 为可选
- 详情页:在动作区(「立即玩」旁,而不是共创信息卡——那张卡讲改编关系)新增收藏切换。三态严格区分:collected=true → 「已收藏」点击取消;collected=false → 「收藏」点击收藏;**缺字段(匿名 / 无效 token 被按匿名处理)绝不落成「未收藏」**,按钮 title 标注「登录后可收藏」,点击走既有登录门禁且不发请求
- 乐观更新 + 回滚:先切换本地态,失败回滚到服务端投影并用服务端 message 提示(role=status);成功以服务端返回的 collected 为准
- 广场卡片:卡片本身没有操作区,按「没有就别硬塞」不动
- 我的收藏:落在 /games/mine 的页签(「我的作品」/「我的收藏」)。理由:两者都是登录后的个人内容、该页已有登录门禁;且不需要新路由,避免牵动「路由表 + nginx×3 + Pingora allowlist」这组必须同批登记的清单。复用公开目录同一套卡片(shared 的 GameCard + GameCover),空态/失败重试/登录态照既有写法
- 分页按「将来会有 cursor」的形态写:读 nextCursor,非空才渲染「加载更多」并在点击时追加;服务端当前恒为 null,不伪造分页数据
- 文案统一「收藏 / 已收藏」(不用需求文档旧词「收录」)
- 测试:详情页收藏四例(已收藏→取消 / 未收藏→收藏 / 缺字段走门禁且零请求且不渲染已收藏 / 失败回滚+服务端文案);我的收藏两例(空态且默认页签不预取 / 列表渲染+卡片点击跳详情+无 cursor 不出现「加载更多」)
|
||
|
|
4b1f24a8fc |
feat(游戏共创): 收录(收藏)契约与文档同步(块 3/3)
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/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 / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
- `shared-contracts`:新增 `GameDistributionCollectionState { collected, replayed: Option<bool> }` 承载 PUT/DELETE 共用形状(PUT 才发 `replayed`);既有 `GameDistributionGameSummary` 增 `collected: Option<bool>`(公开详情登录时才带)——该类型只被 api-server 测试与 `GameDistributionListResponse` 引用,加字段不影响任何现有发送方
- `packages/shared` TS 镜像同步(`{ collected: boolean; replayed?: boolean }` 与 `GameDistributionGame.collected?: boolean`),并按既有约定登记进 `scripts/check-game-distribution-dto-parity.mjs`(PAIRS + 手拼响应构建器);注意 `json!` 字面量里不插注释行(parity 脚本抓顶层键时不剥注释,这个坑今天踩过一次)
- 技术方案:`§2.4` 入口矩阵补「收藏按钮 / 我的收藏(登录)与我的作品页同行风格」;`§3.4` 接口表补三条路由(含 404/409 语义、PUT 要求幂等键而 DELETE 不要求及理由、`my-collections` 只含公开作品且不删行)与公开详情 `collected` 的可见性口径;`§7` 把「收录/收藏」从范围外移除并标注已纳入落地
- 数据契约表目录:新增 `game_distribution_collection` 小节(主键确定性、两个索引、为什么不删行、为什么不建唯一索引),供 `check:spacetime-schema` 守卫通过(94 tables)
- 门禁:DTO parity 0(**49 组** Rust/TS 一致,较本轮前 +7);`check:spacetime-schema` 0(94 tables,对照新 merge-base `51cb05f4`);`check:encoding` 0;`git diff --check` 0
|
||
|
|
cc7d214136 |
feat(游戏共创): 收录(收藏)接口:三条路由 + 公开详情 collected(块 2/3)
- 新增 `collections` 路由组(整组 `require_bearer_auth` + `add_no_store_response_headers`,用户态读不会被任何缓存复用):
· `PUT /api/game-distribution/games/{game_id}/collection` → `{ collected: true, replayed }`,要求 `Idempotency-Key`(沿用既有 `idempotency_key(&headers)?`);同键重放 `replayed=true`,同键不同请求(摘要绑定 `(userId, gameId)`)→ 409,重复收藏(不同键)只留一行且成功
· `DELETE .../collection` → `{ collected: false }`,**不要求 Idempotency-Key**:按确定性主键删除本就幂等(不存在也算成功),没有「重放 vs 新意图」可区分;也**不要求作品仍公开**(下架后仍可清理)
· `GET /api/game-distribution/my-collections` → `{ games: [<public_game_payload>…], nextCursor: null }`,逐条复用既有公开目录的组装方式,只含当前公开可读作品
- 公开详情 `GET /games/{game_id}` 增量:**已认证**返回 `collected: true|false`;**匿名不返回该键**(选这种口径的理由:`false` 会把「未登录」说成「没收藏」,客户端无法区分就会渲染出错误的按钮态);携带无效/过期 token 时按**匿名**处理(沿用 `record_game_play` 的取舍——公开详情匿名可读,不该因此掉 401),因此该响应与纯匿名逐字节相同(单测断言)。实现复用既有 `auth::optional_access_token_from_headers`(`auth.rs:223`),**没有自造 extractor**;值来自新 procedure(真实投影),**未改动既有公开快照契约**
- **共享缓存核实(硬性项)**:公开详情所在的 `public_games` 路由组带 `add_no_store_response_headers`;`app::build_router` 只做 merge/背压/错误归一化/request_id/tracing/`attach_request_context`,**没有任何响应体缓存或预渲染**;本模块唯一进程内缓存是 `RELEASE_PACKAGE_CACHE`(键 = OSS 对象键、值 = 发行包字节),与 per-user JSON 无关。结论:**该路径无共享缓存,不需要绕开**
- 错误码:作品不存在 → 404;未公开/已软删除/无当前公开版本 → 409(文案「作品状态不允许收藏(未公开或已软删除)」刻意含「状态」而不含「已被删除」,以命中既有映射的 409 分支而非 404 分支)
- 测试(本文件内,新增 5 条):三条路由无 Bearer → 401 且 `no-store`;404/409/摘要不一致 409 的映射;摘要绑定 `(user, game)` 的幂等隔离;PUT/DELETE 的载荷形状;公开详情「匿名无 collected 且与目录负载逐字节相等、登录时 Some(true)/Some(false) 各出现且只多这一个键」
- 门禁:`cargo test -p api-server game_distribution` **70 passed**(含新增 5 条);`cargo check --all-targets` 0
|
||
|
|
77c30bb7b2 |
feat(游戏共创): 收录(收藏)数据模型与绑定(块 1/3)
- `spacetime-module`:新增表 `game_distribution_collection`(`collection_id` 主键、`user_id` / `game_id` 各具名 btree 索引、`created_at`)。**防重靠确定性主键** `collection_id = "{user_id}:{game_id}"`(与 `profile_save_archive.archive_id` 同一写法):同一 (用户, 作品) 在结构上不可能有第二行,不依赖「事务里先查后写」(那种写法只在单写者假设下成立,分片/并发时两个事务都可能先查到不存在再各写一行);正因主键即约束,**不需要**再建 `(user_id, game_id)` 唯一索引,两个索引只服务两个读取方向
- 下架(未公开/软删除)**不删除**收藏行:收藏是用户态事实,读侧投影时才按当前公开性过滤,作品重新公开后同一行自动回到列表(注释写明)
- 新增动作常量、4 个输入类型、3 个结果类型、3 个事务(collect / uncollect / list)+ 读态 helper + 4 个 procedure;`uncollect` 按确定性键删除且**不要求作品仍公开**(下架后拒绝取消会给用户留下清理不掉的脏行);`list` 走 `user_id` 索引 + 既有 `public_game_distribution_snapshot` 投影,只含当前公开可读作品
- 新增 `module-game-distribution/src/collection.rs`:两条纯函数(`game_distribution_collection_id`、`game_distribution_collection_visible`)+ 单测——后者用「同一行、四种可见性输入」直接钉住「已收藏 → 下架 → 列表不含 → 重新公开 → 列表又含」这条链路,不必起真库
- `migration.rs`:新表进白名单并补中文注释
- `spacetime-client`:record + 3 个 mapper + 4 个方法 + 2 个 RecordInput,并按既有做法只保留 `module_bindings/game_distribution*`(13 个新文件)与 `module_bindings.rs` 的生成改动、还原其余 rustfmt 漂移
- 门禁:wasm build 0;`cargo check --all-targets` 0;`cargo test -p module-game-distribution` 75 passed;`cargo test -p spacetime-module` 273 passed / 1 ignored(含 4 条新事务结构断言);`cargo fmt --all -- --check` 0
|
||
|
|
c3030eddba |
chore(游戏共创): 收尾清掉最后一条旧口径注释(成品包只作可玩参考 → 生成脚手架 + 参考副本)
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 / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (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
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
|
||
|
|
f94946ef8e |
feat(游戏共创): 注册并处理 Fork 深链 genarrative://fork?gameId=…
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
冻结约定:`genarrative://fork?gameId=<gameId>`,同时接受 `genarrative://fork/<gameId>`。
方案(用官方两个插件,不手搓单实例与注册表):
- `tauri-plugin-single-instance`(开 `deep-link` feature)**第一个注册**:Windows/Linux 上深链是
「带 URL 启动第二个进程」,该插件把第二个实例的 argv 转交给已有实例,并(feature 生效时)
交给 deep-link 插件发事件——否则用户点第二次链接会再开一个窗口。macOS 上它用 Unix socket
做同样的收口(系统本身也只会有一个 .app 实例)。
- `tauri-plugin-deep-link`:`tauri.conf.json > plugins.deep-link.desktop.schemes = ["genarrative"]`。
· macOS:打包器按该配置往 `Info.plist` 注入 `CFBundleURLTypes`(插件 `config.rs` 里那句
`// Used in tauri-bundler` 是代码级证据),运行时由系统把 URL 交给已运行的 .app。
· Windows:运行时 `register_all()` 写 `HKCU\Software\Classes\genarrative`(`URL Protocol` 标记 +
`DefaultIcon` + `shell\open\command`,不需要管理员);安装器侧同样按该配置注册。
· Linux:运行时写用户级 `applications/<exe>-handler.desktop` 并调 xdg-mime(AGC 未以此平台分发,
但仍走同一条运行时路径)。
- 冷启动:插件在插件初始化阶段就解析 argv 并暂存,而应用 `setup` 晚于插件,因此
`initialize_fork_deep_link` **先取 `get_current()`**、再 `on_open_url` 订阅后续链接(漏了前者会
丢冷启动那一次)。
- 收到 URL 后:聚焦主窗口(unminimize + show + set_focus)→ 发 `game-fork-deep-link` 事件
`{ gameId | message }` → 渲染层把请求存进 store 并切回首页;**不自动下载**,用户按
「Fork 到我的项目」才走与手工输入完全相同的提交路径。正停在项目工作区时不强行切走
(避免把用户从进行中的项目里踢出来),请求留在 store 里等用户回到首页。
- 非法链接:解析出可读原因(空链接 / 非 genarrative 方案 / 非 fork 形式 / 缺 gameId / gameId 不合法)
一并聚焦窗口并交给渲染层展示,不做静默失败。
测试:`fork_game_id_from_deep_link` 的合法(两种形式、大小写、多余参数、game_id/id 别名)与
非法(空、错方案、错形式、缺 gameId、`../escape`、URL 编码斜杠、非 URL)各一组;`gameId` 形状
判据与取件路径共用(`is_safe_fork_game_id`);TS 侧覆盖载荷解析、订阅映射、深链预填后**不自动
下载**、非法链接展示原因且不请求。
|
||
|
|
96309c895c |
新增「原版与二创对比」页与路由登记(含 nginx×3 + Pingora allowlist)
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
- 新增路由 /games/compare(stage game-compare):STAGE_ROUTE_ENTRIES + SelectionStage 类型 + 壳层 lazy 引入/导航回调/渲染分支 + 页面标题,四处同批登记 - 三份 nginx SPA allowlist(deploy/nginx/genarrative.conf、deploy/nginx/genarrative-dev-http.conf、deploy/container/nginx.conf)与 Pingora MAIN_SPA_PATHS 同步放行 /games/compare(保持既有排序):check:nginx-spa-routes 18 SPA routes、check:pingora-route-parity 均绿 - 对比页左右两侧各自取数与降级:任一侧不可读(不存在/未公开/已软删除)或没有可玩版本时只降级那一侧,另一侧照常;显示标题、作者与代际;桌面左右并排、窄屏上下堆叠 - iframe 复用游玩页同一份嵌入:抽出 GamePlayFrame(sandbox=allow-scripts、allow=fullscreen、referrerPolicy=no-referrer、.game-player-frame),游玩页改为渲染它,不再存在第二套嵌入逻辑 - 入口:二创作品详情页在存在父作品时给出「与原版对比」;族谱节点仅在其父作品可见时给出同一入口 - 测试:对比页两侧渲染与 iframe 复用属性、单侧降级后另一侧照常;详情页入口(有/无父作品);族谱节点入口(父可见才出现);路由与标题登记;壳层「族谱节点→对比页」导航与对比 stage 渲染 - 顺手:按 eslint 自动修复两个文件的 import 排序 |
||
|
|
4cf00ac07d |
refactor(游戏共创): Fork 口径收敛为「把整个工程复制到你的项目里继续改造」
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
产品裁定:不再对外解释「可玩参考 + 素材 / 不能一键复刻工程 / 需自建合规工程」那套口径。 统一一句话:**Fork = 把整个工程复制一份到你的项目里继续改造(与 git fork 同理)**,动作名统一 叫 Fork。必要告知只保留一句:开启共创并上传工程时,整个工程(含素材与文档)会对他人可见, 且不可撤销。 - 入口(首页):`从平台作品 Fork` + 角标 `Fork`,说明压成一句「把平台上的作品整个工程复制到 你的项目里继续改造(像 git fork)。输入要 Fork 的作品 ID 或作品链接即可。」;按钮 `Fork 到我的项目`、加载态「正在 Fork:下载、校验并创建项目…」;成功态只留 「已创建项目《X》,Fork 自平台作品 <gameId>(来源已记录在 …fork-source.json)」, 删掉按取件形态分岔的长句。 - 发布面板:授权区只留一句「授权非「禁止共创」即允许他人 Fork 你的作品;开启共创并上传工程时, 整个工程(含素材与文档)会对他人可见,且不可撤销。」;确认项压成一句 「我已确认工程里没有不愿公开的内容,同意随本次发布公开整个工程(含素材与文档);一经发布 不可撤销。」,其后一行写「默认已勾选,可随时取消;不勾选则本次不上传工程源码。」 - 错误与进度文案:取件失败四态改为 Fork 措辞(`无法 Fork` / `该作品当前不能被 Fork(未公开、 已下架或没有公开版本)`),读取/下载/响应类错误改为 `读取 Fork 信息失败` / `下载 Fork 内容失败`, 超限提示改为「Fork 内容超过客户端下载上限,无法完成」;「未上传工程源码」提示改为 「他人 Fork 时只能拿到平台已发布的成品」;默认项目名前缀 `改编项目` → `Fork 项目`; 记录标签 `项目改编来源记录` → `项目 Fork 来源记录`。 - 实现事实(成品包形态的脚手架 + `reference/<gameId>/`)保留在 Rust 文档注释里,不再作为对外 表述;`collect_project_bundle_files` 等实现注释不动。 - 测试:入口用例改为断言一句话口径与「Fork 自平台作品」并断言旧的解释性表述已消失;面板用例 断言新的简短告知与「默认已勾选,可随时取消;不勾选则本次不上传工程源码」;错误文案断言同步。 |
||
|
|
928fb0e616 |
Fork 入口主路径改为唤起客户端(genarrative://fork),未失焦才降级为手动路径
- 新增 src/components/game-distribution/gameForkProtocol.ts 收口唤起:协议 genarrative://fork?gameId=<id>,用顶层 location.href 赋值(协议未注册时桌面浏览器只是「什么都不发生」,不会把页面导航走也不会被弹窗拦截,失败可观察),并导出降级等待窗口 FORK_LAUNCH_FALLBACK_DELAY_MS=1200 - 详情页点击「Fork 这个作品」直接唤起;失焦(window blur)或页面转入后台(visibilitychange=hidden)都视为客户端接手 → 只给状态反馈,不出降级面板 - 未失焦 → 经过降级窗口后展示手动面板(作品 ID / 完整作品链接 / 复制按钮 / 客户端指引 / 一句话告知) - 移动端与未知平台不尝试唤起(协议未注册时移动浏览器行为不可控),直接给手动路径 - 每条路径都有可观察反馈:正在唤起 / 已唤起 / 没有检测到客户端 / 当前设备无法直接唤起;定时器与失焦监听的清理覆盖卸载、重复点击、超时三条路径 - 顺手修掉同文件一个既有竞态:作者昵称补查的断言紧跟 findByRole(effect 尚未发出请求)导致偶发 0 次调用、让整份文件的门禁随机变红,改为 waitFor 等待 |
||
|
|
b6fe63b551 |
文案收敛:动作名统一 Fork,去掉「可玩参考 + 素材 / 不能重新发布」那套表述
- 动作名统一:「改造这个作品」→「Fork 这个作品」,「登录后可改造」→「登录后可 Fork」 - 面板指引改为「在陶泥儿客户端里打开「从平台作品开始创作」,粘贴下面的作品 ID 或作品链接。」 - 对外口径统一为「Fork = 把整个工程复制一份到你的项目里继续改造(与 git fork 同理)」,并保留一句话必要告知:整个工程(含素材与文档)复制后对他人可见,且不可撤销 - 删除「成品包只能可玩参考 + 素材」「不能直接再次发布」「参考产物在 reference/<作品ID>/」等展开说明(冻结口径 1) - 测试同步:断言新文案与「不可撤销」告知,测试名与注释不再出现「改造」 |
||
|
|
df30fdeec7 |
Merge remote-tracking branch 'origin/master' into fix/run-preview-refresh-reload
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 6m54s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m54s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m12s
Project CI / Frontend tests (pull_request) Successful in 2m54s
Project CI / Backend tests (pull_request) Successful in 7m34s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m7s
Project CI / Repository checks (pull_request) Successful in 6m58s
Project CI / Native shell tests (pull_request) Successful in 9m32s
|
||
|
|
bdcefe91d1 |
Merge remote-tracking branch 'origin/master' into feat/game-fork
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m31s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m20s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m3s
Project CI / Frontend tests (pull_request) Successful in 2m54s
Project CI / Backend tests (pull_request) Successful in 7m36s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m26s
Project CI / Repository checks (pull_request) Successful in 6m25s
Project CI / Native shell tests (pull_request) Successful in 9m34s
# Conflicts: # deploy/container/nginx.conf # deploy/nginx/genarrative-dev-http.conf # deploy/nginx/genarrative.conf # server-rs/crates/api-server/src/modules/game_distribution.rs # src/components/game-distribution/GameDetailPage.tsx # src/components/game-distribution/GameDistributionPages.test.tsx # src/components/platform-entry/PlatformEntryActiveFlowShell.tsx |
||
|
|
430d983f65 |
修正原生壳预览边界守卫以接受刷新重载变量
Project CI / Backend tests (pull_request) Failing after 24s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m47s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m38s
Project CI / Repository checks (pull_request) Failing after 14s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m11s
Project CI / Frontend tests (pull_request) Successful in 2m14s
Project CI / Native shell tests (pull_request) Successful in 8m40s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m25s
- 预览框 src 断言改为两种形态都接受:旧的 `src={embeddedUrl}`,或 `src={iframeUrl ?? undefined}`
- 新形态额外要求 `iframeUrl` 由 `useMemo` 定义、且定义体内引用 `embeddedUrl`(只改名不算通过)
- 其余断言(`resolveEmbeddedPreviewUrl(` / loopback 校验 / sandbox / 单 iframe 与单挂载)原样保留
- 背景:14283db94 为「刷新运行画面」引入 iframeUrl,撞红了 Native shell tests 的
Run native shell contract gates(missing src={embeddedUrl});只接受新形态会让 master 反过来红
|
||
|
|
51cb05f418 |
补充创作者主页与关注粉丝工程文档 (#638)
Project CI / AI game creator shell Rust crates (push) Successful in 5m56s
Project CI / AI game creator shell Rust lane 2/2 (push) Successful in 6m36s
Project CI / AI game creator shell Rust lane 1/2 (push) Successful in 7m37s
Project CI / Backend tests (push) Successful in 9m22s
Project CI / Frontend tests (push) Successful in 4m40s
Project CI / AI game creator shell web tests (push) Successful in 3m50s
Project CI / Repository checks (push) Successful in 6m30s
Project CI / Native shell tests (push) Successful in 8m32s
本 PR 补齐创作者主页与关注粉丝功能的产品合同和工程设计,供后续按里程碑实施;本次只修改文档。 桌面导航第四项进入自己的创作者主页,“我的”移到第五项。游戏详情可进入作者主页并关注/取消关注;自己或他人的关注、粉丝列表均公开可查看,点击用户头像或昵称可进入其主页。本人支持取消/重新关注、回关和移除粉丝,并明确两个关注方向独立。 工程设计包含关系表与 DTO、认证和事务边界、跨页状态同步、共享组件、深链及验收要求,拆分关系查询和页面交互两个里程碑。按用户要求,游戏列表沿用最多 48 项的现有限制,不增加游戏目录分页改造。 验证: - 已合入最新 origin/master(21c79f54a);共享决策记录冲突保留双方新增内容。 - npm run check:encoding 通过。 - npm run check:doc-index 通过。 - git diff --check 与暂存差异检查通过。 - 相对 master 仅六份文档发生变化;没有业务代码或 schema 修改,未执行业务测试或部署。 Reviewed-on: #638 Co-authored-by: Linghong <ink29535@proton.me> Co-committed-by: Linghong <ink29535@proton.me> |