diff --git a/docs/project-memory/plans/【实施计划】AGC发行包分片续传上传-2026-09-23.md b/docs/project-memory/plans/【实施计划】AGC发行包分片续传上传-2026-09-23.md index 21aa5c760..cad6a3437 100644 --- a/docs/project-memory/plans/【实施计划】AGC发行包分片续传上传-2026-09-23.md +++ b/docs/project-memory/plans/【实施计划】AGC发行包分片续传上传-2026-09-23.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Version | 1.0 | -| Status | runtime-smoke-passed(存储原语、服务端入口、原生上传器、渲染进程接线与真实栈分片续传 smoke 均已落地) | +| Status | implemented-awaiting-runtime-acceptance(存储原语、服务端入口、原生上传器、渲染进程接线与真实栈分片续传 smoke 均已落地) | | Date | 2026-09-23 | | Parent Milestone | `docs/project-memory/plans/【里程碑】AGC发行包分片续传上传-2026-09-23.md` | diff --git a/docs/project-memory/plans/【实施计划】AGC客户端更新切换到官方更新插件-2026-09-17.md b/docs/project-memory/plans/【实施计划】AGC客户端更新切换到官方更新插件-2026-09-17.md index 4e93b3844..7049bfb55 100644 --- a/docs/project-memory/plans/【实施计划】AGC客户端更新切换到官方更新插件-2026-09-17.md +++ b/docs/project-memory/plans/【实施计划】AGC客户端更新切换到官方更新插件-2026-09-17.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --------- | ----------------------------------------------------------------------------------- | | Milestone | `docs/project-memory/plans/【里程碑】AGC客户端更新切换到官方更新插件-2026-09-17.md` | -| Status | ready | +| Status | implemented-awaiting-runtime-acceptance | | Owner | Codex | ## 修改边界 @@ -35,3 +35,11 @@ - Windows 安装模式由插件配置决定(本里程碑固定 `quiet`,与旧 PowerShell `/S` 一致);若改为 `passive` 会多出安装进度条 UI。 - 插件在 Windows 上安装成功后自行退出进程,前端不再有机会更新界面;提示面板的完成态只在 macOS / Linux 可见。 - 回滚点:改动集中在客户端与配置,回滚后即可退回自研链路;旧 OSS `agc/latest.json` 在发布管线渠道化前不删除。 + +## 本轮复核(2026-09-24) + +状态原为 `approved` / `ready`(规范评审态),实现其实已经落地,本轮按当前工作树复核并改记为 `implemented-awaiting-runtime-acceptance`: + +- 原生侧接入官方插件:`apps/ai-game-creator-shell/src-tauri/Cargo.toml` 有 `tauri-plugin-updater = "2.11.0"`;`tauri.conf.json` 打开 `createUpdaterArtifacts` 并写入 `plugins.updater.pubkey` 与渠道端点。 +- 自研更新链路已删除:`download_ai_game_creator_update` / `install_ai_game_creator_update` / `check_ai_game_creator_update` 在 `src-tauri/src` 与 `src` 内均无命中;前端更新服务 `src/services/appUpdate.ts` 只消费官方插件包,而该包是 IPC 薄壳,网络与安装都在 Rust 侧。 +- 未执行(需要签名私钥与发布授权):真实签名打包、真实 OSS 发布、安装后真机升级与回滚。 diff --git a/docs/project-memory/plans/【实施计划】AGC工作区偏好IO下沉Rust-2026-09-23.md b/docs/project-memory/plans/【实施计划】AGC工作区偏好IO下沉Rust-2026-09-23.md new file mode 100644 index 000000000..83b87c146 --- /dev/null +++ b/docs/project-memory/plans/【实施计划】AGC工作区偏好IO下沉Rust-2026-09-23.md @@ -0,0 +1,54 @@ +# 【实施计划】AGC 工作区偏好 IO 下沉 Rust + +Version: `v1` +Status: `implemented-awaiting-runtime-acceptance` +Date: `2026-09-23` +Parent Spec: `docs/project-memory/plans/【里程碑】AGC工作区偏好IO下沉Rust-2026-09-23.md` + +## 修改边界 + +1. 新增 `src-tauri/src/workspace_preferences.rs`:定义版本化 AppData JSON、路径规范化、原子写入、command 输入/输出和偏好变更事件。 +2. 在 `main.rs` 注册 typed commands;首页自动建项和模板建项由 Rust command 内部读取项目创建目录,保持现有目录安全校验。 +3. `features/app-shell/model.ts` 保留纯校验/展示模型,移除 `localStorage` 读写,新增一次快照/迁移所需的 invoke façade。 +4. `useProjectCreationDirectory.ts` 与 `useRecentProjects.ts` 订阅 Rust 事件,首次挂载读取一次快照;浏览器/Vitest 无 Tauri 时保留内存 fallback,不恢复周期轮询。 +5. 增加 Rust/React 定向测试,更新现有 localStorage 断言为 command/event 合同;不修改 auth、wallet、prompt polish 和 Home draft。 + +## 实施顺序 + +- 先完成 Rust 偏好模块和单测,再注册 command/event,最后切换 React 读取/写入边界。 +- 先让自动建项闭环不再传 `projectsRoot`,再切换模板建项;确认旧参数仍兼容后删除前端读取。 +- 迁移旧 localStorage 只做一次、在 Tauri 环境显式触发;迁移失败不得覆盖 Rust 已存在值。 + +## 验证命令 + +```text +cargo fmt --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml -- --check +cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml workspace_preferences +npm exec vitest run -- apps/ai-game-creator-shell/tests/projectCreationDirectory.test.ts apps/ai-game-creator-shell/tests/recentProjectsHook.test.tsx +npm --prefix apps/ai-game-creator-shell run typecheck +npm run ai-game-creator-shell:check:web +npm run check:encoding +npm run check:doc-index +git diff --check +``` + +## 风险与回滚点 + +- AppData 偏好文件不可写时,读取继续返回安全空态,写入返回可见错误;React 不回退到隐式 `localStorage` 持久化。 +- 旧 localStorage 键可能包含无效或已不存在的路径,迁移只接受规范化绝对路径,并受 Rust 端每次建项校验保护。 +- 若事件订阅竞态导致首次通知丢失,挂载快照读取作为唯一补读;不引入 `setInterval`。 + +## 当前验证记录 + +- Rust workspace preference 定向测试:`3 passed / 0 failed`。 +- React 定向测试:`projectCreationDirectory.test.ts` 与 `recentProjectsHook.test.tsx` 共 `7 passed`。 +- AGC TypeScript:`npx tsc -p tsconfig.json --noEmit` 通过;定向 Prettier 与新 Rust 模块 rustfmt 检查通过。 +- 完整 `npm --prefix apps/ai-game-creator-shell run typecheck` 已通过,发行 typed command allowlist 已同步。 + +## 本轮取证(2026-09-24) + +- 行为合同 1/2/3(偏好文件缺失不阻断启动、最近工作区最多 8 条去重幂等、创建目录只表达意图且建项仍过 Rust 门禁):`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- workspace_preferences --test-threads=1` → **6 passed**。 +- 范围项(React 不再直接访问 `localStorage`、建项不再由 React 传 `projectsRoot`):`rg localStorage apps/ai-game-creator-shell/src` 只剩 `features/app-shell/workspacePreferences.ts` 的旧键迁移 shim(`isTestRuntime()` 门控);`rg projectsRoot apps/ai-game-creator-shell/src` **0 命中**。 +- 前端 façade:`npx vitest run tests/recentProjectsHook.test.tsx tests/projectCreationDirectory.test.ts --root apps/ai-game-creator-shell` → **5 + 4 passed**(命令/事件投影、失败重试与偏好读写)。 +- Rust 侧变异验证(2026-09-24):把 `MAX_RECENT_WORKSPACES` 从 8 改成 16 后,`normalizes_recent_paths_with_a_strict_eight_item_limit` 立刻红(`left: 10, right: 8`),说明「最近项目最多 8 条」这条上限确实被钉住;改回后 `workspace_preferences` 定向用例 exit 0。 +- 仍未验证(需要真实客户端):多窗口并发改偏好、事件丢一次后的受控快照读取、真实建项落到用户所选目录。 diff --git a/docs/project-memory/plans/【实施计划】AGC工作区网络IO下沉Rust-2026-09-23.md b/docs/project-memory/plans/【实施计划】AGC工作区网络IO下沉Rust-2026-09-23.md new file mode 100644 index 000000000..de0a65ed3 --- /dev/null +++ b/docs/project-memory/plans/【实施计划】AGC工作区网络IO下沉Rust-2026-09-23.md @@ -0,0 +1,79 @@ +# 【实施计划】AGC 工作区网络 I/O 下沉 Rust + +Version: `v1` +Status: `implemented-awaiting-runtime-acceptance` +Date: `2026-09-23` +Parent Spec: `docs/project-memory/plans/【里程碑】AGC工作区网络IO下沉Rust-2026-09-23.md` + +## 修改顺序 + +1. 先盘点现有 Rust HTTP/auth/session facade 与发行/资源命令,冻结 typed request/response 和事件名。 +2. **发行链路(已完成)**:新增 `game_distribution_publish.rs` typed facade 和五个 Tauri commands;创建游戏、创建版本、分片上传、送审、灰度读取、资料建议、封面价格/生成与队列收口均由 Rust 持有。保留既有分片上传 command 与幂等/续传语义,React service 只保留 `invoke` façade。 +3. **模型目录闭环(已完成)**:官方 `/api/llm/models` 改由 Rust typed command 持有会话与 HTTP;React 只消费目录投影。素材库/素材直传仍待后续切片。 +4. 为每条命令补 Rust 单测、前端 invoke/事件测试和静止状态无轮询断言。 +5. 更新主规范、事件目录与验证记录;账户/钱包调用保留并明确排除。 + +## 验证命令 + +- `npm --prefix apps/ai-game-creator-shell run typecheck` +- `npm run ai-game-creator-shell:check:web` +- `cargo fmt --all --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml -- --check` +- 相关 Rust `cargo test --locked` 定向测试 +- `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml game_distribution_publish` +- `npx vitest run apps/ai-game-creator-shell/tests/gameDistributionPublish.test.ts` +- `npm run check:encoding` +- `npm run check:doc-index` +- `git diff --check` + +## 回滚点 + +保留现有 Rust 上传命令和旧 TS service 的提交边界;迁移每个 typed facade 时先让 Rust command 可独立读取/写入,再切换 React 调用方,避免出现“旧网络调用已删但新 command 未注册”的窗口。不得用重新启用 React 轮询作为回滚。 + +## 当前批次证据:官方模型目录 + +- 新增 Tauri typed command load_game_creator_llm_models;Rust 持有当前平台会话、固定 API origin、Bearer、AGC marker、响应 envelope 解析、1 MiB 响应上限和账号身份代次复核。 +- React llmModelCatalog 在 Tauri 官方目录路径只通过 typed invoke 读取;自定义模型继续使用本地配置,浏览器无 native host 时保留兼容读取。 +- Rust 定向测试 4/4、clientApi 与 ConversationModelSelect 定向测试 38/38、appSurface 211 passed / 9 skipped。 +- typecheck 的 tsc 与 skill-pack、check:encoding、check:doc-index、git diff --check 通过;check-config 仍受共享工作树既有发行命令缺口阻断,发行资料 facade 另按本实施计划处理。 + +## 当前切片证据(2026-09-23) + +- `apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs` 读取 Rust `platform_session` 的 user/token/origin,只接受结构化参数;每个 HTTP 步骤复核身份代次,保留 Bearer、`X-Genarrative-Client: agc`、响应 envelope、幂等键和稳定错误分类。 +- `publish_local_project_game` 在 Rust 内完成本地包暂存、创建 game/version、分片续传和 submit;渲染进程不再取得 token、origin 或整包字节。已有 `upload_local_project_game_package` command 未改动。 +- 封面异步任务由 Rust 以有界 1.6 秒间隔、20 分钟/800 次上限等待;React 不再执行远端 job 轮询。 +- `npx vitest run apps/ai-game-creator-shell/tests/gameDistributionPublish.test.ts`:7 passed;`npm exec tsc -- --noEmit -p apps/ai-game-creator-shell/tsconfig.json` 通过。 +- `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml game_distribution_publish`:4 passed;`rustfmt --edition 2021 --check` 针对新 Rust 文件通过。 +- 尚未宣称全部工作区网络已迁移:素材库/素材上传、账户刷新、错误上报及其它 clientApi 链路仍在各自里程碑范围内;真实 Tauri + Provider/生产发行 smoke 仍待环境验证。 +- 发行 facade 追加 session identity 保护:每个 JSON 步骤与每个分片前重新读取当前 token,换号/origin 变化失败关闭;旧 native-only 分片 command 保留显式 token 兼容,不属于 React 工作区入口。 + +## 当前切片证据:编辑器素材库与预览 + +- 范围补充:远程导入同步改成 assetId-only,删除旧 remoteAssets/objectKey/downloadUrl 透传。UI 继续传现有 import policy/requirements;Rust 复用账户素材导入核心,按实际字节落实单文件/批次上限和正式 kind,预览字节不作为导入事实。预览切换/卸载后迟到响应不能回写。 +- Rust 新增 read_editor_asset_library:复用当前账号 session、账户素材静态图片筛选和安全投影,只返回 folders/assets 展示字段、稳定 assetId、尺寸/大小和 previewAvailable;不序列化 objectKey、imageSrc、assetObjectId、token 或本地路径。 +- Rust 新增 read_editor_asset_preview:按当前账号 assetId 重新解析权威素材,有界下载并校验图片大小、Content-Type/magic、重定向和 session identity,返回 data URL;没有稳定 objectKey/legacy path 的记录失败关闭。 +- React AssetImporter/ImageImporterPreview 改为 editorAssetHost typed invoke;旧 loadEditorAssetLibrary/resolveClientAssetReadUrl 不再由该入口调用。import_ui_editor_assets 的旧 remote 入参保留,downloadUrl 暂由 Rust 返回的 data URL 提供,Rust 兼容解析该 data URL,WebView 不再直接发素材预览/导入网络请求。 +- Rust 定向资源投影/预览 data URL/legacy import 测试 13/13、AssetImporter 定向测试 4/4、AGC typecheck tsc/skill-pack 通过;待补完整 web gate、编码/文档索引/diff 检查后再提交该切片验收。 + +## 当前切片证据:素材上传与错误报告(2026-09-24) + +- 新增 `src-tauri/src/platform_asset_upload.rs` 与命令 `upload_platform_media_asset`:凭证申请、对象存储表单直传、confirm、会话身份复核和地址白名单全部在 Rust;React `assetDirectUpload.ts` 只读取用户选择的文件字节并提交结构化元数据,不再持有 token、拼 URL 或发平台请求。 +- 新增 `src-tauri/src/error_report/submit.rs` 与命令 `submit_error_report`:Rust 持有 origin、Bearer、稳定 submissionId(按事件 ID 派生)与 envelope 解析;React 只提交脱敏事件、说明与诊断日志,`errorReporting.ts` 不再 import `fetchClientHttp` / `getStoredAuthAccessToken` / `getClientServerBaseUrl`。 +- 渲染层偏好补齐:`chatPromptPolish` 的「不再提醒」从 localStorage 迁到 Rust 客户端偏好(`set_chat_prompt_polish_reminder_disabled` + 既有偏好事件),组件改为「挂载读一次快照 + 订阅事件」,并修掉迟到快照覆盖用户新选择的竞态。 +- 验证:Rust 定向 `platform_asset_upload` 3/3、`error_report::submit` 4/4、`workspace_preferences` 4/4;前端定向 `assetDirectUpload` 3/3、`errorReporting` 11/11、`ErrorReportDialog` 3/3、`chatPromptPolish` 18/18、`resourceReferenceInput` 43/43;`npm run ai-game-creator-shell:check:web` 1857 passed / 14 skipped;编码、文档索引、`git diff --check`、`cargo fmt --check` 通过。 + +## 当前切片证据:账户与钱包(2026-09-24) + +- 新增 `src-tauri/src/account_api.rs` 与五个命令(recharge-center / wallet-ledger / create order / confirm wechat order / redeem code):Rust 从当前平台会话取 origin 与 Bearer,解析 envelope 并映射稳定错误分类;401 返回 `authentication-required` 由渲染层按既有会话续期链路重试一次,付费订单未知结果不自动重放。 +- 渲染层新增 `src/services/accountHost.ts` 与 `src/services/platformSessionRetry.ts`;`useAccountWallet` 与 `stores/useWalletStore` 改为 typed invoke,`clientApi` 不再承载账户与钱包请求。Direct Codex 的登录失效判定与账户命令共用同一份分类,避免两处口径漂移。 +- 验证:Rust 定向 `account_api` 4/4;前端定向 `accountHost` 3/3、`walletStore` 14/14;`npm run ai-game-creator-shell:check:web` 186 passed / 1857 passed / 14 skipped;编码、文档索引、`git diff --check`、`cargo fmt --check` 通过。 +- 仍未迁移:登录、验证码、refresh、登出与开发服务器选择,见 `【里程碑】AGC认证会话与账户网络下沉Rust-2026-09-24.md`;真实账号登录/续期/微信支付仍需环境证据。 + +## 本轮取证(2026-09-24) + +- 验收 1(React 不再直连):`rg "requestClientApi|fetchClientHttp|accessToken|refreshToken" apps/ai-game-creator-shell/src` → **0 命中**;`rg projectsRoot apps/ai-game-creator-shell/src` → 0 命中。 +- 验收 3(静止时无 React 轮询):`rg setInterval apps/ai-game-creator-shell/src` 只剩两类非远端任务——计时/动画(`AuthenticatedClient` 的登录耗时与验证码倒计时、`useLiveNow`、`useDesignReplyAnimation`、`DirectProjectConversation` 的本地时钟)和拖拽重复器(`TransformEditor`)。 +- 验收 4/5 的定向用例:`npx vitest run tests/gameDistributionPublish.test.ts tests/assetDirectUpload.test.ts tests/pluginHost.test.ts tests/directActiveTurns.test.tsx tests/resourceCanvasAssetGenerationQueue.test.ts tests/recentProjectsHook.test.tsx tests/projectCreationDirectory.test.ts --root apps/ai-game-creator-shell` → **7 文件 / 63 passed**。 +- 变异验证(2026-09-24):拿掉 `platform_asset_upload::validate_upload_host` 的「只允许回环 http 与 `*.aliyuncs.com` https」判定后,`validates_upload_hosts_without_accepting_arbitrary_origins` 精确挂在 `https://evil.example.com/upload` 那条断言上,证明这条防任意主机上传的用例不是空跑;改回后该用例与 `corrupt_or_foreign_session_files`(见认证里程碑)各自 exit 0。 +- 脱敏用例的强度复核(2026-09-24):禁用 `error_report::sanitize::redact_urls` 后,只有 `keeps_api_route_while_redacting_url_origin_and_query`(精确相等断言)变红,`redacts_credentials_urls_paths_and_ids` 仍然通过——`PATH_PATTERN` 的盘符分支大小写不敏感,`http://` 里的 `p:` 也会命中并把整段 URL 吞成 `http`,所以「URL 被换成占位符」这件事当时没有被断言到。已给该用例补一条 `assert!(sanitized.contains(""))`:规则禁用时新断言精确变红,恢复后 `error_report` 定向用例全绿(sanitize 4 条 + submit 4 条)。 +- 变异验证之三/四(2026-09-24):① 去掉 `error_report::submit::stable_submission_id` 里的 `ids.sort_unstable()` 后,`submission_id_is_stable_and_order_independent` 立刻红(同一批事件两种顺序给出两个不同 `agc-error-report-*`),证明「同批重放命中服务端幂等键」的排序不变性被守住;② 把 `account_api::map_http_error` 的 401 分支前缀 `authentication-required: ` 去掉后,`expires_and_permissions_keep_stable_categories` 精确变红——这正是渲染层 `platformSessionRetry` 用来决定「续期一次再重放」的分类契约,两端各有一条用例钉住。改回后 `account_api::tests` 与 `error_report::submit::tests` 各自 exit 0。 +- 仍未验证(需要真实环境):真实 OSS 发行包上传与送审、真实账户下的发行资料生成、发布取消/未知结果的端到端表现。 diff --git a/docs/project-memory/plans/【实施计划】AGC更新发布管线渠道化-2026-09-17.md b/docs/project-memory/plans/【实施计划】AGC更新发布管线渠道化-2026-09-17.md index 94fb23092..897834307 100644 --- a/docs/project-memory/plans/【实施计划】AGC更新发布管线渠道化-2026-09-17.md +++ b/docs/project-memory/plans/【实施计划】AGC更新发布管线渠道化-2026-09-17.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --------- | ------------------------------------------------------------------------- | | Milestone | `docs/project-memory/plans/【里程碑】AGC更新发布管线渠道化-2026-09-17.md` | -| Status | ready | +| Status | implemented-awaiting-runtime-acceptance | | Owner | Codex | ## 修改边界 @@ -35,3 +35,12 @@ - 签名缺失即失败关闭:构建机未注入签名私钥时发布中止,不产生半成品清单。 - 渠道端点写进产物:渠道名一旦发布不可改名(改名等于已发布客户端再也找不到更新)。 - 回滚点:发布脚本与流水线都在本里程碑内,回滚后客户端仍可用原先的自研清单协议;迁移桥可独立停用。 + +## 本轮复核(2026-09-24) + +状态原为 `approved` / `ready`(规范评审态),实现其实已经落地,本轮按当前工作树复核并改记为 `implemented-awaiting-runtime-acceptance`: + +- 渠道单点定义 `apps/ai-game-creator-shell/scripts/channel-identity.mjs`;`build-release.mjs` 由它解析渠道,渠道清单 URL 与构建期端点随渠道变化。 +- 流水线渠道参数:`jenkins/Jenkinsfile.ai-game-creator-shell-build` 有 `AGC_UPDATE_CHANNEL`(dev / release / 自定义小写名)并把部署目标绑定为渠道对应的构建分区。 +- 定向测试(本轮实跑):`node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs apps/ai-game-creator-shell/scripts/release-oss.test.mjs apps/ai-game-creator-shell/scripts/prepare-macos-codex.test.mjs apps/ai-game-creator-shell/scripts/cargo-features.test.mjs` → **60 passed / 0 failed**,含 `channel manifest carries version, platform keys and signature`、`missing signature fails the channel manifest closed`、`channel manifest URL and build-time endpoint follow the channel`、`release windows uploads only its own partition and cannot write the dev bridge`。 +- 未执行(需要签名私钥与发布授权):真实签名打包、真实 OSS 上传、各渠道真机升级验证。 diff --git a/docs/project-memory/plans/【实施计划】AGC本地状态事件化第一批-2026-09-23.md b/docs/project-memory/plans/【实施计划】AGC本地状态事件化第一批-2026-09-23.md new file mode 100644 index 000000000..8715daab5 --- /dev/null +++ b/docs/project-memory/plans/【实施计划】AGC本地状态事件化第一批-2026-09-23.md @@ -0,0 +1,49 @@ +# 【实施计划】AGC 本地状态事件化第一批 + +Version: `v1` +Status: `implemented-awaiting-runtime-acceptance` +Date: `2026-09-23` +Parent Spec: `docs/project-memory/plans/【里程碑】AGC渲染层事件化与Rust数据源-2026-09-23.md` + +## 修改边界 + +1. `src-tauri/src/agent/direct_runtime` 与 `runtime_driver`:增加活动回合快照事件,在注册、状态变化和 guard 释放后发送;不改变既有 Tauri command 与运行语义。 +2. `src/features/agent-runtime/directActiveTurns.ts`:订阅事件并去重,首次只读一次快照,移除 5 秒定时器。 +3. `src-tauri/src/asset_generation_tasks.rs`:账本写入成功后发送项目任务变更事件;`resourceCanvasAssetGenerationQueue.ts` 通过事件唤醒单次读取,恢复/丢事件仍允许显式读取。 +4. `src-tauri/src/plugin_host.rs`:插件状态变更后发送插件快照事件;`RuntimeConfigDialog.tsx` 订阅事件并移除 1 秒定时器。 +5. 对应 Vitest/Rust 测试与必要的 AGC 文档更新。 +6. `direct_thread_manager`、Tauri handler 与聊天订阅 hook 补幂等 unsubscribe;`App.tsx` 保存失败后解除自触发重写,定向覆盖故障注入与策略读取单飞。 + +## 实施顺序 + +- 先增加 Rust 事件与单元测试,再改 React 订阅,避免出现“旧读取已删、新事件未发”的中间态。 +- 事件 handler 只接受当前项目/当前代次,按内容签名去重;清理函数必须幂等。 +- 事件不可用时只保留首次快照与用户触发的显式刷新,不增加隐式定时器。 + +## 验证命令 + +- `npm exec vitest run -- apps/ai-game-creator-shell/tests/directActiveTurns.test.tsx apps/ai-game-creator-shell/tests/resourceCanvasAssetGenerationQueue.test.ts apps/ai-game-creator-shell/tests/tauriEventSubscription.test.ts` +- `npm exec vitest run -- apps/ai-game-creator-shell/tests/appSurface.test.ts` +- `npm --prefix apps/ai-game-creator-shell run typecheck` +- 对 AGC 壳 Rust 运行相关单测分片或定向 `cargo test` +- `npm run check:encoding` +- `git diff --check` + +## 回滚点 + +事件名与 payload 是内部 Tauri 合同;若运行时验证发现订阅或事件顺序问题,可保留 Rust 事件发送、临时恢复一次性快照读取,并回退 React reducer,不修改持久化账本和既有 command。 + +## 当前验证记录 + +- `npm run ai-game-creator-shell:check:web`:类型检查、配置契约和 AGC Web 全量门禁通过,`1858 passed / 14 skipped`。 +- 定向事件/生命周期测试:`41 passed`;其中活动回合 `11/11`、资源生成队列 `19/19`、线程订阅 `2/2`。 +- Rust 定向测试:Direct Thread Manager `13/13`、活动回合快照 `1/1`、素材生成账本 `15/15`、插件宿主 `17/17`。 +- `cargo fmt --check`、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` 通过。 +- 未验证真实 Provider、打包后 Tauri 窗口时延和外部发行网络迁移;账户、素材上传、错误上报与发行网络仍按后续里程碑保留。官方模型目录已在本轮单独由 `load_game_creator_llm_models` 下沉到 Rust,但不能据此宣称全部 React 网络 I/O 已归 Rust。 + +## 本轮取证(2026-09-24) + +- 验收 1(活动回合与素材任务不再定时轮询):`rg setInterval apps/ai-game-creator-shell/src` 全仓只剩计时/动画与拖拽重复器;`directActiveTurns.ts` 走 `DIRECT_ACTIVE_TURNS_CHANGED_EVENT` 事件 + 单飞读取并在注释里写明「不恢复定时轮询」,`resourceCanvasAssetGenerationQueue.ts` 走 `game-creator-asset-generation-task-changed` 事件(Rust 在账本状态变更处 emit),事件桥不可用时才回退注入的 wait。 +- 验收 3/7(订阅先于快照、重复事件不换数组身份、卸载后迟到事件不写回、subscriber 幂等注销):`npx vitest run tests/directActiveTurns.test.tsx tests/resourceCanvasAssetGenerationQueue.test.ts --root apps/ai-game-creator-shell` → **11 + 19 passed**;Rust 侧 `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- direct_thread_manager --test-threads=1` → **13 passed**。 +- 验收 4(插件状态:进入读一次 + 事件更新 + 显式刷新):`npx vitest run tests/pluginHost.test.ts --root apps/ai-game-creator-shell` → **14 passed**。 +- 仍未验证(需要真实客户端):长回合中插件状态事件与素材任务事件的真实时序、真实 Provider 生成下的任务账本事件密度。 diff --git a/docs/project-memory/plans/【实施计划】AGC渠道安装身份隔离-2026-09-21.md b/docs/project-memory/plans/【实施计划】AGC渠道安装身份隔离-2026-09-21.md index 982d7cb08..cee6730b0 100644 --- a/docs/project-memory/plans/【实施计划】AGC渠道安装身份隔离-2026-09-21.md +++ b/docs/project-memory/plans/【实施计划】AGC渠道安装身份隔离-2026-09-21.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Milestone | `docs/project-memory/plans/【里程碑】AGC渠道安装身份隔离-2026-09-21.md` | -| Status | ready | +| Status | implemented-awaiting-runtime-acceptance | | Owner | 当前 Agent | ## 修改边界 @@ -54,3 +54,8 @@ - `channel-identity.mjs` 是展示名单一来源。发布构建将同一 `productName` 同时注入 Tauri 安装配置、原生窗口标题和 `VITE_AGC_PRODUCT_NAME`;React 自绘标题栏及关于/运行时配置展示从该注入值读取。 - 因此 Windows NSIS 默认生成的快捷方式、开始菜单/卸载注册表展示名随 Tauri `productName` 变为 `陶泥儿开发版`;未新增自定义注册表或快捷方式实现。 - 静态 Tauri 基线配置同步为 `陶泥儿开发版`,本地壳与正式 `dev` 包的显示名保持一致。 + +## 本轮复验(2026-09-24) + +- `node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs apps/ai-game-creator-shell/scripts/release-oss.test.mjs apps/ai-game-creator-shell/scripts/prepare-macos-codex.test.mjs apps/ai-game-creator-shell/scripts/cargo-features.test.mjs`:**60 passed / 0 failed**,含「release / beta 的 Windows 与 macOS 构建只写自己渠道分区、不能写 dev 桥」四条分区隔离用例。 +- 仍未执行:真实渠道打包(需要签名私钥与发号/上传授权)、双渠道真机并存安装、macOS 构建节点实跑。 diff --git a/docs/project-memory/plans/【实施计划】AGC画布交互稳定性修复-2026-09-16.md b/docs/project-memory/plans/【实施计划】AGC画布交互稳定性修复-2026-09-16.md index 73de10aa7..ddbc9da7c 100644 --- a/docs/project-memory/plans/【实施计划】AGC画布交互稳定性修复-2026-09-16.md +++ b/docs/project-memory/plans/【实施计划】AGC画布交互稳定性修复-2026-09-16.md @@ -1,7 +1,7 @@ # AGC 画布交互稳定性修复实施计划 - Date: 2026-09-16 -- Status: awaiting-runtime-acceptance +- Status: implemented-awaiting-runtime-acceptance - Milestone: [画布交互稳定性修复](./【里程碑】AGC画布交互稳定性修复-2026-09-16.md) ## 修改顺序与边界 diff --git a/docs/project-memory/plans/【实施计划】AGC统一错误诊断与验收反馈-2026-09-15.md b/docs/project-memory/plans/【实施计划】AGC统一错误诊断与验收反馈-2026-09-15.md index 031cd576c..34d5b68d0 100644 --- a/docs/project-memory/plans/【实施计划】AGC统一错误诊断与验收反馈-2026-09-15.md +++ b/docs/project-memory/plans/【实施计划】AGC统一错误诊断与验收反馈-2026-09-15.md @@ -1,7 +1,7 @@ # AGC 统一错误诊断与验收反馈实施计划 Version: 1.0 -Status: active +Status: implemented-awaiting-runtime-acceptance Date: 2026-09-15 Parent Milestone: `【里程碑】AGC统一错误诊断与验收反馈-2026-09-15.md` @@ -33,3 +33,19 @@ Parent Milestone: `【里程碑】AGC统一错误诊断与验收反馈-2026-09-1 - 若前端详情读取失败,仍展示安全 `publicText`,不阻塞错误终态。 - 若素材身份无法映射,继续失败关闭并记录明确 code,不回退为路径字符串通过。 - 回滚可删除新事件写入和详情入口,保留旧 `failure.json` 读取兼容。 + +## 当前进度(2026-09-24) + +- 已落地并验证:统一错误事件模型与脱敏(`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 runtime_error` → 7 passed)、DirectProject 失败安全投影与项目内 sidecar、下一轮诊断上下文、app-server 终态与超时分类、试玩 attempt 上限。 +- 本轮补缺口:渲染层取回 `detailRef` 的口径抽成 `apps/ai-game-creator-shell/src/services/agentRuntimeErrorDetail.ts`,新增 `tests/agentRuntimeErrorDetail.test.ts`(4 条);Rust 侧新增 `direct_codex_failure_text_keeps_the_detail_ref_marker_for_the_renderer` 钉住同一份文案。两侧用例互相引用用例名,改文案或改解析都会变红(文案标记过去只在渲染层内联正则里,两侧都没有测试)。 +- 仍未完成的是验收标准 6 的交互项:诊断正文目前随失败文案一次性读回并展示,尚未做成「点击详情后才读取」的展开入口。要继续的话先在主规范里定交互,再改 UI;在那之前本里程碑保持 `active`,不按已完成收口。 + +## 报告缺口关闭(2026-09-24) + +上一轮记录里「验收标准 6 的交互项未完成」已经实现,本轮把计划从 `active` 改记为 `implemented-awaiting-runtime-acceptance`: + +- 修掉一个真实缺陷:Native 已经下发 `direct-codex-failure:v2`(在 v1 之上多了 `code=` 与末尾 `;详情:`),但渲染层映射只认 v1,任何 DirectProject 失败都被兜底成「执行失败,请稍后重试」,Rust 精心产出的阶段、摘要与建议全部被丢掉。现在 v1 / v2 共用同一套脱敏与阶段映射(v2 用例在 `tests/agentRuntimeModel.test.ts`,移除 v2 分支该用例变红;2026-09-24 复核:把正则里的 `:v2` 改成 `:v3` 后该文件精确 1 条失败、其余 18 条通过,声明已被独立复现)。 +- 失败提示不再预读也不内联诊断正文:控制器只把安全 `publicText` 交给面板,`detailRef` 与提示文案分开持有;聊天状态栏下方新增「查看详情 / 收起详情」入口,展开时才调用 `read_agent_runtime_error_detail`(原生命令仍做目录校验与二次脱敏),读不到只显示一句说明,不影响提示本身。 +- 钉住这条交互的用例:`tests/appSurface/chat-composer.suite.ts` 的「失败提示保留可执行原因,诊断正文只在「查看详情」时读取」(断言点击前没有 `read_agent_runtime_error_detail` 调用、正文不在提示或历史消息里,点击后按 `projectPath + detailRef` 读取并展示,再点收起)。 +- 自动化:`npx vitest run tests/agentRuntimeModel.test.ts tests/agentRuntimeErrorDetail.test.ts`(23 passed)、`npx vitest run tests/appSurface.test.ts`(191 passed / 9 skipped)、`npx tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit`、`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 runtime_error`(7 passed)。 +- 仍未验证(需要真实账号与 Provider):真实失败回合下从提示进入详情、以及下一轮追问从历史读取失败证据的端到端表现。 diff --git a/docs/project-memory/plans/【实施计划】AGC认证会话与账户网络下沉Rust-2026-09-24.md b/docs/project-memory/plans/【实施计划】AGC认证会话与账户网络下沉Rust-2026-09-24.md new file mode 100644 index 000000000..ad313e521 --- /dev/null +++ b/docs/project-memory/plans/【实施计划】AGC认证会话与账户网络下沉Rust-2026-09-24.md @@ -0,0 +1,65 @@ +# 【实施计划】AGC 认证会话与账户网络下沉 Rust + +Version: `v1` +Status: `implemented-awaiting-runtime-acceptance` +Date: `2026-09-24` +Parent Spec: `docs/project-memory/plans/【里程碑】AGC认证会话与账户网络下沉Rust-2026-09-24.md` + +## 修改边界 + +1. 新增 `src-tauri/src/auth_session.rs`:AppData 私有凭据文件(`client-session.json`)、 + origin 校验、refresh cookie 解析与原子写入、并发续期合并、401 续期重放与事件发送。 +2. 新增 `src-tauri/src/account_api.rs`:profile dashboard / 充值中心 / 创建订单 / + 确认微信充值 / 钱包账单 / 兑换码 typed commands。 +3. `src-tauri/src/main.rs` 注册新 command 与新模块;`platform_asset_upload.rs`、 + `game_distribution_publish.rs`、`llm_catalog.rs`、`error_report/submit.rs` 改为经 + `auth_session` 获取会话并在 401 时续期重放一次,而不是只读当前快照。 +4. 渲染层 `clientAuth.ts`、`clientHttp.ts`、`clientApi.ts`、`platformSession.ts`、 + `AuthenticatedClient.tsx`、`useAccountWallet.ts`、`stores/useWalletStore.ts` + 改为 typed invoke / 事件; + +## 修改顺序 + +1. 先落 Rust 凭据存储与 origin 校验,配单元测试;此时尚无调用方,不改变现役行为。 +2. 落认证 commands 与事件,Rust 内部安装/清除本地运行时会话(复用既有 + `install_platform_session` / `clear_platform_session` 与 Runner 传播),保留旧 command。 +3. 落账户/钱包 commands,复用同一会话获取与 401 续期重放。 +4. 切换渲染层:`AuthenticatedClient` 与钱包改为 command/事件;删除 token 持久化与 + `fetchClientHttp` 直连调用点。 +5. 最后清理:删除 `clientApi`/`clientHttp` 中已无调用方的直连实现与旧 localStorage 迁移键, + 更新主规范与共享记忆。 + +## 验证命令 + +- `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml auth_session` +- `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml account_api` +- `npm --prefix apps/ai-game-creator-shell run typecheck` +- `npx vitest run apps/ai-game-creator-shell/tests/clientAuth.test.ts apps/ai-game-creator-shell/tests/accountWallet.test.tsx` +- `npm run ai-game-creator-shell:check:web` +- `cargo fmt --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml -- --check` +- `npm run check:encoding`、`npm run check:doc-index`、`git diff --check` + +## 风险与回滚点 + +- refresh 凭据落盘是本计划的最高风险项:必须使用与其它 AGC 私有文件相同的 ACL/普通文件 + 门禁,并且只写 refresh cookie(不写 access token)。 +- 401 续期重放必须只重放一次;付费创建订单的未知结果按 `result-unknown` 处理,不自动重放。 +- 回滚点:保留旧 `install/clear_platform_account_session` 与旧 `clientAuth` 分支直到验收; + 回退时删除 Rust 凭据文件即回到未登录状态。 + +## 当前验证记录(2026-09-24) + +- 新增 `src-tauri/src/auth_session.rs`:AppData 私有 `client-session.json`(Unix 0o600、Windows reparse 检查、私有目录树与原子替换)、origin 校验(纯 origin、非本机必须 HTTPS、发布构建限渠道 origin)、refresh cookie 解析与轮换、登录/验证码/续期/登出 HTTP、`install_client_session_locally` / `clear_client_session_locally` 复用既有 Runner 传播与 app-server 停机路径。 +- 新增 6 条 typed command:`read_client_auth_state`、`refresh_client_auth_session`、`send_client_phone_login_code`、`login_client_with_password`、`login_client_with_phone_code`、`logout_client_session`,并发出 `agc-client-auth-state-changed` 状态事件(只含状态、用户展示字段与 origin)。 +- 路由语义分离:会话路由的 401/403 归类成 `authentication-required` / `permission-denied`(可据此清会话),登录路由保留服务端原因(「手机号或密码错误」),避免把用户输入错误显示成登录失效。 +- Direct 回合保活改为 Rust 持有:`DirectTaonierActiveInvocationGuard` 在登记回合时启动 `spawn_client_session_keepalive`(30 秒 tick、按 access token 签发时间 4 分钟后才真正续期,drop 即 abort),渲染层删除 5 分钟 `setInterval` 与 `DIRECT_CODEX_SESSION_KEEPALIVE_MS`;401 补续期重试路径保留。\n- 渲染层:`clientAuth.ts` 收敛为 typed invoke façade;`platformSession.ts` 收敛为身份代次投影(Rust 事件驱动,同一账号续期不推进代次);`AuthenticatedClient` 的三态恢复、登录、登出全部改走 command/事件;服务器选择迁到 Rust 客户端偏好(`set_client_server_selection`)。 +- 删除:`services/clientApi.ts`、`clientHttp` 的 `fetchClientHttp`/超时封装/服务器选择 localStorage、`clientAuth` 的 token 持久化、`install/clear/read platform_account_session` 三条渲染层写入入口(Rust 认证内部直接调用)。渲染层 `src` 内已无 `fetch(`、无 access token / refresh cookie 读写。 +- 验证:Rust 定向 `auth_session` 12/12(含并发续期复用、事件不含凭据、保活窗口判定与未初始化不启动任务)、`direct_runtime` 97/97、`workspace_preferences` 6/6、`account_api` 4/4、`platform_asset_upload` 3/3、`error_report::submit` 4/4;前端 `clientAuthHost` 6/6、`conversationModelSelect` 29/29、`useTemplateLibrary` 11/11、appSurface 认证切片 12/12;`npm run ai-game-creator-shell:check:web` 184 passed / 1800 passed / 14 skipped;`cargo fmt --check`、`check:encoding`、`check:doc-index`、`git diff --check` 通过。 +- 未验证:真实账号登录/续期/登出、微信支付、多窗口并发刷新、真实 Provider 回合跨 token 过期的保活,仍需环境证据。Direct 回合的 5 分钟保活仍由渲染层定时触发(真正续期已在 Rust),后续可改为由 Rust 在出站调用前按到期时间自续期。 + +## 本轮取证(2026-09-24) + +- 原生定向(同一批过滤一次跑完 42 项):`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- workspace_preferences account_api platform_asset_upload auth_session error_report::submit direct_thread_manager --test-threads=1` → **42 passed**。 +- 分组明细:`auth_session::` **12 passed**(会话存储所有权与权限、origin 校验、6 条命令的错误分类)、`account_api::` **4 passed**、`platform_asset_upload::` **3 passed**、`workspace_preferences` 6、`direct_thread_manager` 13、`error_report::submit` 含在其中。 +- 结构:`rg "accessToken|refreshToken" apps/ai-game-creator-shell/src` → 0 命中(渲染层不再持有凭据);`localStorage` 只剩偏好迁移 shim。 +- 仍未验证(需要真实账号):真实登录/续期/登出、微信支付、多窗口并发刷新、真实 Provider 回合跨 token 过期。 diff --git a/docs/project-memory/plans/【实施计划】AGC资源JSON语义识别-2026-09-16.md b/docs/project-memory/plans/【实施计划】AGC资源JSON语义识别-2026-09-16.md index 5c2947540..90a699529 100644 --- a/docs/project-memory/plans/【实施计划】AGC资源JSON语义识别-2026-09-16.md +++ b/docs/project-memory/plans/【实施计划】AGC资源JSON语义识别-2026-09-16.md @@ -1,7 +1,7 @@ # AGC 资源 JSON 语义识别实施计划 - Date: 2026-09-16 -- Status: awaiting-runtime-acceptance +- Status: implemented-awaiting-runtime-acceptance - Milestone: [AGC 资源 JSON 语义识别](./【里程碑】AGC资源JSON语义识别-2026-09-16.md) ## 实施边界 diff --git a/docs/project-memory/plans/【实施计划】AGC资源kindRust枚举与ts-rs绑定-2026-09-15.md b/docs/project-memory/plans/【实施计划】AGC资源kindRust枚举与ts-rs绑定-2026-09-15.md deleted file mode 100644 index 33870c0f0..000000000 --- a/docs/project-memory/plans/【实施计划】AGC资源kindRust枚举与ts-rs绑定-2026-09-15.md +++ /dev/null @@ -1,61 +0,0 @@ -# 【实施计划】AGC 资源 kind Rust 枚举与 ts-rs 绑定 - -| 字段 | 值 | -| --- | --- | -| Milestone | `docs/project-memory/plans/【里程碑】AGC资源kind枚举化Rust绑定与内部收紧-2026-09-15.md` | -| Status | complete | -| Owner | Codex | - -## 修改边界 - -允许修改: - -- `server-rs/crates/shared-contracts` 内 GameCreationApp 资源 kind 的独立 Rust 模块; -- shared-contracts 的可选 ts-rs 绑定 feature; -- ai-game-creator-shell 的 shared-contracts feature 引用和生成测试入口; -- shell 内生成的 GameCreationApp kind TypeScript 文件; -- 对应 Rust/TS 定向测试与文档 todo 证据。 - -本切片已落地: - -- `GameCreationAppAssetManifestEntry.kind` 由 `String` 收紧为 `GameCreationAppAssetKind`:这是公开 Rust 类型的破坏性变更,按「不写历史兼容代码」直接改类型,不加兼容层、不做数据迁移;manifest 反序列化未知值收口为 `Unknown`。 -- 上传内容推断的字体写入 `Font`,未知上传类型写入 `Unknown`;图集切片 manifest 写入 `Icon`。 -- shell 内 manifest kind 的写入侧与读取侧统一为正式枚举成员:资源登记、字体导入、direct runtime 产物、平台美术登记与恢复、manifest 必填校验、资源编辑派生、UI 设计桥接与工作流。 -- 资源编辑请求的 `sourceSubtype` 只传正式枚举成员;资源编辑内部源身份拆成「正式 kind / 项目版本 / Agent 回执」三类,项目版本与 Agent 回执不再冒充 manifest kind。 -- ts-rs 绑定改由 `cargo test export_bindings` 生成:枚举自带 `#[ts(export, export_to = …/src/contracts/generated/)]`;退役的 `BindingDTO` / `BindingChange` 不再导出,手写的 `exports_ui_editor_types` 已删除。 -- `packages/shared/src/contracts/generated/` 作为受控生成目录在 `.prettierrc.json` 中使用与 ts-rs 原始输出一致的格式选项,并在 `.gitattributes` 标记为 `linguist-generated`;生成文件仍参与 Prettier/ESLint 检查,`cargo test export_bindings` 可幂等复现且不再污染工作树。 -- `Unknown` 表示解析边界无法判定的输入;写入方可以保留该结果,但必须明确决定拒绝写入或交由后续归类,不得把它误写成某个具体 kind。 -- shell TS 资源引用边界消费生成绑定,资源 kind 集合从生成的 union 穷举派生,并为未知值保留原始值与上下文日志。 -- api-server 图片快速编辑来源校验改为严格解析 `GameCreationAppAssetKind`,只允许共享枚举的静态图片成员;删除原有 legacy/兼容字符串白名单,退役值不再放行。 - -明确不修改: - -- `category`、`mediaType`、`source.kind`、`source.generationKind`; -- api-server 的其他资源 taxonomy、SpacetimeDB schema、OpenAPI;本切片只改图片快速编辑的 GameCreationApp manifest 来源校验。 -- shared-contracts 的 canonical alias 表与读时自愈:alias 表已删除,严格解析和 `Unknown` 口径保持不变; -- `packages/shared` 中重复的资源 kind 手写契约与其余前端裸 `string` 字段(后续切片)。 - -## 实现顺序 - -1. 新建独立 kind 模块,定义当前正式成员:17 个现有 canonical kind + `font` + `Unknown`,serde 使用 kebab-case。 -2. 为 enum 增加可选 ts-rs derive,默认 shared-contracts 构建不引入 ts-rs。 -3. 让 shell 的 shared-contracts 依赖打开绑定 feature;生成目录 2026-09-17 起收敛到 `packages/shared/src/contracts/generated/`(kind 是跨端契约,不再放 shell 私有目录)。 -4. 增加 Rust serde round-trip 与 Unknown 解析/序列化测试;TS 侧不再手写生成值集合,改为从生成 union 穷举派生。 - 未知值通过 `parse_with_context` 收口到 `Unknown`,并把原始值与解析上下文交给壳层注册的 `app_log!` 回调(2026-09-17 起不再用 `tracing` / `kind-observability`)。 -5. 运行 shared-contracts 与 shell 定向测试,并用 `export_bindings` 复现生成文件;完成后将稳定结论回写里程碑并关闭本计划。 - -## 验证命令 - -1. `cargo fmt --all -- --check` -2. `cargo test --locked -p shared-contracts game_creation_app --manifest-path server-rs/Cargo.toml` -3. `cargo test --locked -p shared-contracts --features ts-bindings export_bindings --manifest-path server-rs/Cargo.toml`(生成 `packages/shared/src/contracts/generated/GameCreationAppAssetKind.ts`) -4. `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml export_bindings`(生成 shell 自己的 ts-rs 绑定) -5. `npx vitest run apps/ai-game-creator-shell/tests/assetKind.test.ts packages/shared/src/contracts/gameCreationApp.test.ts`(解析 Rust 源码的 `assetKindCanonicalMapping.test.ts` 2026-09-17 已删除:手写词汇表被移除后它没有比对对象) -6. `npm run check:encoding` -7. `git diff --check` - -## 风险与回滚点 - -- 风险:ts-rs 默认生成 enum/union 形态与 serde rename 不一致;必须以生成文件和 round-trip 测试为准。 -- 风险:shared-contracts 被 SpacetimeDB/WASM 使用;ts-rs 必须是 optional feature,默认构建不可依赖。 -- 回滚点:本切片仅新增 enum/绑定,不改变现有 manifest JSON 解析;若生成链路不稳定,可回滚本提交而不影响现有业务。 diff --git a/docs/project-memory/plans/【实施计划】AGC资源kind词汇审计与绑定架构-2026-09-15.md b/docs/project-memory/plans/【实施计划】AGC资源kind词汇审计与绑定架构-2026-09-15.md deleted file mode 100644 index 2376edc3c..000000000 --- a/docs/project-memory/plans/【实施计划】AGC资源kind词汇审计与绑定架构-2026-09-15.md +++ /dev/null @@ -1,43 +0,0 @@ -# 【实施计划】AGC 资源 kind 词汇审计与绑定架构 - -| 字段 | 值 | -| --- | --- | -| Milestone | `docs/project-memory/plans/【里程碑】AGC资源kind枚举化词汇审计与绑定架构-2026-09-15.md` | -| Status | complete | -| Owner | Codex | - -## 修改边界 - -允许修改: - -- 主规范中的资源 kind 当前口径; -- `docs/project-memory/plans/` 下本任务的里程碑/实施计划; -- `docs/project-memory/todos/` 下本任务的扫描清单; -- 为审计提供只读扫描脚本(如确有必要,脚本也只覆盖 shell)。 - -明确不修改: - -- 已完成的 `apps/ai-game-creator-shell` 业务收口不再属于未决范围;后续只允许按新里程碑变更; -- server-side 代码、OpenAPI、SpacetimeDB schema; -- MIME、`source.kind`、`generationKind` 和其他字符串领域。 - -## 实现顺序 - -1. 按“manifest asset kind / 其他字段 / 仅文本同名”三类扫描 shell 的 `kind`、`assetKind`、`asset_kind` 和 manifest 构造器。 -2. 对每个候选值回到调用上下文,标记生产写入、读取投影、协议输入、测试 fixture 或纯文本/路径。 -3. 对照 api-server 当前有效资源 kind,排除 legacy、billing/storage synthetic taxonomy 和开放字段。 -4. 记录正式候选 enum、Unknown 输入行为、保留字符串字段和后续 PR 边界。 -5. 形成下一里程碑的文件级修改顺序和验证矩阵;本里程碑结束后暂停,等待验收。 - -## 验证命令 - -1. `rg -n 'kind|assetKind|asset_kind' apps/ai-game-creator-shell/src apps/ai-game-creator-shell/src-tauri/src` -2. `npm run check:doc-index` -3. `npm run check:encoding` -4. `git diff --check` - -## 风险与回滚点 - -- 风险:同一字符串可能是 manifest kind、workflow kind 或路径名;任何未回到上下文确认的替换都禁止进入代码。 -- 风险:shared-contracts 被多个 server crate 使用;ts-rs 生成必须通过 feature/独立入口隔离默认构建。 -- 回滚点:本里程碑只有文档和审计清单变更;若词汇边界未能闭合,删除本计划和 todo,不进入代码里程碑。 diff --git a/docs/project-memory/plans/【实施计划】AGC资源菜单收纳-2026-09-17.md b/docs/project-memory/plans/【实施计划】AGC资源菜单收纳-2026-09-17.md index 6a8060348..f9bd5a8b6 100644 --- a/docs/project-memory/plans/【实施计划】AGC资源菜单收纳-2026-09-17.md +++ b/docs/project-memory/plans/【实施计划】AGC资源菜单收纳-2026-09-17.md @@ -2,6 +2,8 @@ 对应:[里程碑](./【里程碑】AGC资源菜单收纳-2026-09-17.md),Issue #409,产品已确认方案 A。 +Status: implemented-awaiting-runtime-acceptance + ## PR #410 CI 修复 以远端合并提交 959beebf 为基线:修复菜单文件 import 排序、Web 角标结构断言、活动回合空快照与晚到请求竞态;窗口发布次数断言对齐稳定快照合同。原生 HTTP scope 检查对齐官方 updater 当前权限,不恢复退役 OSS 白名单;Rust 图集测试补齐显式切片模式与 strict schema 字段,不放宽正式校验。按故障项定向测试后运行前端全套及原生契约检查;Rust 使用独立 target,实际未执行的检查必须单独列出。推送需再次确认。 @@ -14,3 +16,10 @@ 4. 并行执行定向 Vitest、AGC 类型检查、编码与文档索引检查,再自审整体调用链。 风险:portal 浮层点击外部判定、缩放角标与拖拽冲突、原测试依赖完整工具栏。回滚仅撤销本分支 UI 与文档修改;无数据迁移。首个检查点为组件用例通过,第二个为工作台集成与类型检查。真实客户端未测则明确保留待验收状态。 + +## 本轮复验(2026-09-24) + +- 共用收纳控件与 UI 基元:`npx vitest run packages/shared/src/components/OverflowActions.test.tsx packages/shared/src/components/ui.test.tsx` → **14 passed**(浮层开关、外部关闭、键盘、视口约束与表格/标签等基元语义)。 +- AGC 资源画布菜单与卡面:`npx vitest run tests/resourceCanvasBottomToolbar.test.tsx tests/resourceCanvasCardName.test.tsx tests/resourceCanvasToolbarModel.test.ts`(`--root apps/ai-game-creator-shell`)→ **39 passed**。 +- 全量界面门禁:`npm run ai-game-creator-shell:check:web` → 185 files passed / 1 skipped、1806 tests passed(含工作台整表回归)。 +- 仍未验收(人工、需要真实客户端):真实客户端视觉、原生保存对话框、触摸板操作手感。 diff --git a/docs/project-memory/plans/【实施计划】AGC音频生成进入后台任务账本-2026-09-20.md b/docs/project-memory/plans/【实施计划】AGC音频生成进入后台任务账本-2026-09-20.md index 6dd0957ea..c1863b6fb 100644 --- a/docs/project-memory/plans/【实施计划】AGC音频生成进入后台任务账本-2026-09-20.md +++ b/docs/project-memory/plans/【实施计划】AGC音频生成进入后台任务账本-2026-09-20.md @@ -49,3 +49,9 @@ - 音频自带的 operation 幂等账本与任务账本是两层身份:任务 id 取 operation id,重试复用同一对 operation / 幂等键;不得为「省事」在重试时换新的请求身份(那是一次新的付费生成)。 - 账本 `kind` 为音频时,`restore` 的入口文案若查不到工具栏模型会退化成素材名:入口文案必须由工具栏模型派生,避免恢复后文案漂移。 - 后台跑生成会让「项目 revision CAS」窗口从提交前移到派发时刻:冲突时按失败收口(不静默重试),避免把生成写到非预期基线。 + +## 本轮复验(2026-09-24) + +- 原生后台任务账本:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 asset_generation_tasks` → **15 passed / 0 failed**(任务入账、阶段投影、终态收口与事件通知路径)。 +- 前端队列与面板:`npx vitest run tests/resourceCanvasAssetGenerationQueue.test.ts tests/resourceCanvasAssetGenerationTasksPanel.test.tsx --root apps/ai-game-creator-shell` → 与批量标签同批执行通过(队列单飞、事件唤醒回退、面板状态投影)。 +- 仍未验证(需要真实平台生成与账号):真实音频生成经后台任务账本跑到终态、失败重试与跨项目切换表现。 diff --git a/docs/project-memory/plans/【实施计划】AGC项目创建目录可选-2026-09-17.md b/docs/project-memory/plans/【实施计划】AGC项目创建目录可选-2026-09-17.md deleted file mode 100644 index e3df9b9ce..000000000 --- a/docs/project-memory/plans/【实施计划】AGC项目创建目录可选-2026-09-17.md +++ /dev/null @@ -1,68 +0,0 @@ -# AGC 项目创建目录可选实施计划 - -Version: 1.0 -Status: active -Date: 2026-09-17 -Related Spec: `docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`、`docs/【技术方案】AGC异步操作可恢复闭环-2026-09-14.md` - -## 目标 - -让用户在 AGC 里能自己选项目创建目录:首页「做游戏 / 做方案」自动建项与模板库「使用模板」建项都落在用户选定的目录下;不选时保持 AGC 管理的默认位置(`/projects`),行为与现状一致。 - -## 交接结果 - -- `create_automatic_local_game_project`、`create_automatic_local_game_project_from_template` 新增可选参数 `projectsRoot`;为空时由 Rust 侧回落到默认目录。 -- `pick_local_project_directory` 新增可选参数 `title`(只接受短标题,其余回退「选择游戏项目目录」)。 -- 新增用户偏好「项目创建目录」:`localStorage` 键 `genarrative-ai-game-creator.project-creation-directory.v1`。 -- 入口在客户端设置里:侧边栏「配置」→ 设置分类「工作区」;`RuntimeConfigDialog` 内用 `useProjectCreationDirectory` 展示与改选目录,不经过首页或模板库页头。 -- 首页「做游戏 / 做方案」与模板库「使用模板」建项时读取同一份偏好,用户不需要在建项前再选一次。 - -## 行为契约 - -- 允许的来源只有一个:本机原生目录选择器(`pick_local_project_directory`)。它返回的目录已在选择时按 user-selected 范围做过一次加固,构成「用户显式选择」边界。 -- Rust 侧 `validate_requested_game_project_creation_root` 对传入目录要求:非空、绝对路径、无控制字符、已存在的普通目录(符号链接 / Windows reparse point / 普通文件一律拒绝),并通过 `prepare_game_creator_project_root_for_read`(user-selected 范围的一次性修复)。目录不存在时不代为创建,直接失败。 -- 建出的项目目录仍在所选目录下按 `gameagent-<8位短ID>` 命名,项目名、`.agent` 初始化、首轮投递与既有自动建项完全一致。 -- 偏好只保存「用户意图」,不是授权凭据:存储被外部改动最坏只是回退默认位置或一次可见的建项失败,不会跳过 Rust 门禁。 -- 该偏好是客户端本地设置,不写入 `read_game_creator_app_config` / 保存设置的那份运行时配置:在「工作区」里选择目录当场生效,与「保存设置」按钮无关。 -- 「恢复默认位置」清空偏好即回到应用数据目录;既有项目不迁移。 - -## 步骤 - -1. **Rust 建项入口** - - `commands.rs`:新增 `validate_requested_game_project_creation_root` / `resolve_game_project_creation_root`,`create_automatic_local_game_project` 接受 `projects_root`;`pick_local_project_directory` 接受 `title`。 - - `template_library.rs`:模板建项复用同一解析函数。 - - 交付:两条定向单测(校验矩阵、在指定创建目录下建项)。 - - 验收:`cargo test --bin genarrative-ai-game-creator-shell creation_root` 全绿。 - -2. **前端偏好与入口** - - `features/app-shell/model.ts`:`normalizeProjectCreationDirectory` / `readProjectCreationDirectory` / `writeProjectCreationDirectory` / `projectCreationDirectoryLabel`。 - - `useProjectCreationDirectory`:选择目录、恢复默认、状态文案(失败在设置页字段内可见)。 - - `RuntimeConfigDialog` 新增「工作区」设置分类,承载「项目创建目录」字段与「选择目录 / 恢复默认位置」动作。 - - `useHomeProjectCreation` 与 `useTemplateLibrary` 在建项时带上 `projectsRoot`。 - - 交付:偏好模型 4 项单测、设置页 1 项交互测试、appSurface 1 项「设置里选目录后建项」端到端场景。 - - 验收:`npx vitest run apps/ai-game-creator-shell/tests/projectCreationDirectory.test.ts apps/ai-game-creator-shell/tests/appSurface.test.ts` 全绿。 - -3. **文档与共享记忆** - - 本实施计划;模板库技术方案的命令表补 `projectsRoot`;`decision-log.md` 记录偏好键与命令参数;`pitfalls.md` 说明用户自选目录与 AGC 管理目录的关系。 - - 验收:`node scripts/check-doc-index.mjs` 通过。 - -## 验证命令 - -```bash -cargo check --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell -cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell creation_root -cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell template_library -cd apps/ai-game-creator-shell && npx tsc -p tsconfig.json --noEmit -npx vitest run apps/ai-game-creator-shell/tests -npm run check:encoding -node scripts/check-doc-index.mjs -git diff --check -``` - -手动验收(客户端内):侧边栏「配置」→「工作区」→「选择目录」选 `F:\Projects\我的游戏`,回首页建项后项目目录应为 `F:\Projects\我的游戏\gameagent-<8位>`;模板库「使用模板」建项同样落在该目录;点「恢复默认位置」后再建项回到应用数据目录。 - -## 风险与回退 - -- **自选目录无法加固**:`Documents` 等带受保护继承 ACL 的位置可能加固失败。失败发生在选择器或建项前置校验阶段,报错可见且不会留下半成品项目;用户改选其它目录或用默认位置即可。 -- **偏好漂移**:偏好只是提示值,每次建项都会重新校验;存储被改坏不会绕过门禁。 -- **回退**:删掉偏好键(或点「恢复默认位置」)即回到默认目录;需要彻底移除该能力时,去掉两个命令的可选参数与设置页字段即可,Rust 默认路径逻辑不变。 diff --git a/docs/project-memory/plans/【实施计划】AGC项目定时快照上传-2026-09-17.md b/docs/project-memory/plans/【实施计划】AGC项目定时快照上传-2026-09-17.md index b9cce0d88..779bd520d 100644 --- a/docs/project-memory/plans/【实施计划】AGC项目定时快照上传-2026-09-17.md +++ b/docs/project-memory/plans/【实施计划】AGC项目定时快照上传-2026-09-17.md @@ -1,7 +1,7 @@ # AGC 项目定时快照上传实施计划 Version: 1.0 -Status: active +Status: implemented-awaiting-runtime-acceptance Date: 2026-09-17 Parent Milestone: `【里程碑】AGC项目定时快照上传-2026-09-17.md` @@ -41,3 +41,13 @@ Parent Milestone: `【里程碑】AGC项目定时快照上传-2026-09-17.md` - 数据出境边界(2026-09-22 修订):只上传项目目录内普通文件。`.agent` 承载项目身份与 Agent 状态,整目录上传(含 conversations、logs、runtime、checkpoint、`agent.db`);`.git`、构建产物、临时文件与凭据类文件仍不在白名单内。该修订只作用于快照同步,项目索引与 checkpoint 继续排除整个 `.agent`。 - 服务端未配置 bucket 时客户端必须失败关闭,不能把本地索引推进成"已同步",否则后续同步会漏传。 - 回滚:客户端可停用触发接线(保留模块与测试)即可回到无上传行为;服务端路由与配置项可单独移除,不影响既有 OSS 前缀与错误报告链路。 + +## 本轮验证(2026-09-24) + +- 客户端定向:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml project_snapshot -- --test-threads=1` → 24 passed / 1 ignored(ignored 是真实 OSS live smoke)。 +- 服务端定向:`cargo test -p api-server project_snapshot -- --test-threads=1` → 21 passed / 1 ignored(ignored 需要私有 OSS 环境文件的只读用例)。 +- 本轮补上验收标准 10 的缺口:回收选择抽成纯函数 `plan_project_snapshot_reclamation`,新增 3 条用例覆盖「只回收上一版登记过的对象」「上一版清单读不到时一张都不删」「单轮回收有上限」,并做过变异验证(把保留判据退化成只看路径时该用例变红)。2026-09-24 独立复核:把 `retained` 从 `(路径, 字节数, 摘要)` 三元组退化成只收路径后,`project_snapshot_reclamation_retires_only_objects_the_previous_manifest_registered` 精确红在这一条(同路径但内容已变的 `game/index.html` 旧对象不再进回收计划),另两条回收用例仍绿(2 passed / 1 failed);改回后 3 条全绿、`cargo fmt --check` 通过。 +- 主规范已补「验收面 → 用例」对照表:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的 2026-09-17 小节。 +- 仍未取得证据:真实 OSS 往返、开发态打开项目的索引写入与日志、关窗触发的那一次同步。 + +因此本计划从 `active` 改为 `implemented-awaiting-runtime-acceptance`:行为与定向测试已经落地,缺的是环境侧证据,不替用户签收。 diff --git a/docs/project-memory/plans/【实施计划】AGC首页策划补全入口-2026-09-15.md b/docs/project-memory/plans/【实施计划】AGC首页策划补全入口-2026-09-15.md deleted file mode 100644 index c2d0fbf4f..000000000 --- a/docs/project-memory/plans/【实施计划】AGC首页策划补全入口-2026-09-15.md +++ /dev/null @@ -1,20 +0,0 @@ -Version: 1 -Status: active -Date: 2026-09-15 -Parent Spec: 【里程碑】AGC首页策划补全入口-2026-09-15.md - -## 修改顺序 - -1. 在 `view/home/index.tsx` 增加本地复选框状态与入口切换清理。 -2. 将游戏勾选状态映射到既有 `ProjectStartMode`。 -3. 增加启动模式纯函数测试,覆盖模式分流;首页显示边界和切换清理作为后续组件测试补充项。 - -## 验证 - -- AGC 首页相关定向测试。 -- AGC 前端 typecheck。 -- `npm run check:encoding` 与 `git diff --check`。 - -## 当前验证边界 - -本次已交付测试覆盖 `planning` / `direct-build` 模式分流;“策划补全”复选框的显示边界及切换创作类型后的状态清理尚未有组件级自动化测试,需后续补充 `HomeView` 测试时完成。 diff --git a/docs/project-memory/plans/【实施计划】DirectProject Phaser迁移闭环-2026-09-14.md b/docs/project-memory/plans/【实施计划】DirectProject Phaser迁移闭环-2026-09-14.md index 927385da2..97323865b 100644 --- a/docs/project-memory/plans/【实施计划】DirectProject Phaser迁移闭环-2026-09-14.md +++ b/docs/project-memory/plans/【实施计划】DirectProject Phaser迁移闭环-2026-09-14.md @@ -1,5 +1,5 @@ Version: 1.0 -Status: implemented; real-project runtime smoke pending +Status: implemented-awaiting-runtime-acceptance(真实项目 runtime smoke 待补) Date: 2026-09-14 Parent Milestone: docs/project-memory/plans/【里程碑】DirectProject Phaser迁移闭环-2026-09-14.md diff --git a/docs/project-memory/plans/【实施计划】DirectProject Skill提及输入提示-2026-09-15.md b/docs/project-memory/plans/【实施计划】DirectProject Skill提及输入提示-2026-09-15.md deleted file mode 100644 index 89abee64b..000000000 --- a/docs/project-memory/plans/【实施计划】DirectProject Skill提及输入提示-2026-09-15.md +++ /dev/null @@ -1,27 +0,0 @@ -# 【实施计划】DirectProject Skill 提及输入提示 - -| 字段 | 值 | -| --------- | ----------------------------------------------------------------------------------- | -| Milestone | `docs/project-memory/plans/【里程碑】DirectProject Skill提及输入提示-2026-09-15.md` | -| Status | in-progress | -| Owner | Codex | - -## 代码边界 - -- 前端:`features/project-workspace/ResourceReferenceInput.tsx`、`ResourceReferenceNode.tsx`、`resourceReferences.ts`、生成绑定及聊天入口透传。 -- Rust:`agent/direct_codex_user_item/model.rs`、`validation.rs`、`wire.rs`、`codex_app_server/mod.rs` 与对应测试。 -- 文档:父规范与本里程碑/实施计划。 - -## 小切片顺序 - -1. 先扩展前端 Skill catalog/节点/草稿 content,保持素材行为不变并补前端测试。 -2. 扩展 canonical Rust part 与 ts-rs 绑定,补序列化和失败校验测试。 -3. 接通 Codex wire `type: skill` 转换和受控路径解析,补历史/重放测试。 -4. 完成入口透传、定向验证和文档证据;每个切片单独中文提交。 - -## 验证与回滚 - -- `npm --prefix apps/ai-game-creator-shell run typecheck` -- 相关 Vitest 与 `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml direct_codex` -- `npm run check:encoding`、`npm run check:doc-index`、`git diff --check` -- 每个切片只改计划列出的文件;若 Codex wire 协议或 Skill catalog 来源不确定,停在该切片并先更新规范。 diff --git a/docs/project-memory/plans/【实施计划】DirectProject Thread Manager事件订阅-2026-09-15.md b/docs/project-memory/plans/【实施计划】DirectProject Thread Manager事件订阅-2026-09-15.md deleted file mode 100644 index ba528e84f..000000000 --- a/docs/project-memory/plans/【实施计划】DirectProject Thread Manager事件订阅-2026-09-15.md +++ /dev/null @@ -1,37 +0,0 @@ -# 【实施计划】DirectProject Thread Manager 事件订阅 - -| 字段 | 值 | -| --------- | ---------------------------------------------------------------------------------------- | -| Milestone | `docs/project-memory/plans/【里程碑】DirectProject Thread Manager事件订阅-2026-09-15.md` | -| Status | ready | -| Owner | Codex | - -## 修改边界 - -- 允许修改:DirectProject Rust Thread Manager 深模块、app-server 事件适配、Tauri command/event 桥接、DirectProject 前端订阅/reducer/历史加载、对应测试和主规范。 -- 明确不修改:SpacetimeDB、HTTP API、非 DirectProject Runtime、Codex app-server durable thread、用户可见 JSONL 细节。 -- 保持已有 `.env` 未提交修改,不触碰个人配置。 - -## 实现顺序 - -1. 先新增独立 Rust queue/subscriber 深模块,只承载事件追加、逻辑队头回收、subscriber cursor 锁和纯单测。 -2. 将 app-server 公开事件安全标准化后接入 Thread Manager;在 item 完成持久化成功后追加完成事件,并追加 turn 生命周期事件。 -3. 增加 Tauri `subscribe/consume/readHistory` 命令与 notify 事件,固定错误和 bootstrap 原子边界。 -4. 前端改为 subscriptionId 驱动的 raw event reducer;重进/过期时先 bootstrap,完成后原子替换;历史按 itemId 懒加载。 -5. 移除 DirectProject legacy conversation 读取分支,补齐契约、并发、恢复和失败关闭测试;让初始历史切片的 `hasMore` 独立驱动“显示更早”按钮和滚动入口。 -6. 每个独立切片分别运行定向验证并形成中文小提交;里程碑验收后再清理临时计划。 - -## 验证命令 - -1. `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml` 的 DirectProject/Thread Manager 定向测试。 -2. 相关前端 Vitest 与类型检查。 -3. `npm run check:encoding` -4. `npm run check:doc-index` -5. `git diff --check` - -## 风险与回滚点 - -- 现有 app-server 事件模型与公开 raw event envelope 不完全一致:先在适配层收口,不让协议细节泄漏到前端。 -- 单 Vec 队列不能中间删除;unfinished item 长时间不结束可能暂时 pin 住队头,必须保留可观测上限和测试。 -- Tauri command 无传输层断开回调,subscriber 只通过 queue eviction 失效;测试不能依赖 unsubscribe 或连接断开清理。 -- legacy 删除属于 breaking history 行为;失败关闭测试必须确认不会 fallback 或迁移。 diff --git a/docs/project-memory/plans/【实施计划】DirectProject canonical content严格边界-2026-09-16.md b/docs/project-memory/plans/【实施计划】DirectProject canonical content严格边界-2026-09-16.md deleted file mode 100644 index 6bdbed240..000000000 --- a/docs/project-memory/plans/【实施计划】DirectProject canonical content严格边界-2026-09-16.md +++ /dev/null @@ -1,42 +0,0 @@ -# 【实施计划】DirectProject canonical content 严格边界 - -| 字段 | 值 | -| --------- | ------------------------------------------------------------------------------------------- | -| Milestone | `docs/project-memory/plans/【里程碑】DirectProject canonical content严格边界-2026-09-16.md` | -| Status | implemented | -| Owner | Codex | - -## 实施顺序 - -1. 先把主转换函数改为原样传递 `draft.content`,并在 content-only 测试中覆盖空白 part 保留。 -2. 将最终 content 有效性判断抽为纯函数,接入普通提交、队列入队和其它 Direct Codex 入口。 -3. 删除 Direct Codex 的 `userItem` fallback;首页首轮和队列出队直接构造 canonical user item。 -4. 收敛策略确认重试为复用同一 canonical user item;旧 Supervisor/Planning caller 加 TODO,不改变其非 Direct Codex 行为。 -5. 迁移现有测试 fixture,删除旧字段构造,不增加“字段不存在”测试。 - -## 落地结果 - -- `chatComposerDraftToDirectCodexUserItem` 原样传递 `draft.content`;新增 `directCodexUserItemFromContent` 供 caller 直接构造 canonical item。 -- `ChatComposerDraft` 只保留 `content`;`ResourceReferenceInput` 的对外草稿、`chatPromptDraftKey`、`QueuedChatTurn` 全部改为 content-only。 -- 首页首轮、普通聊天提交、运行中队列出队、策略确认重试都携带同一个 canonical user item;`executeChatAgentReply` 的 `userItem` 兜底分支已删除。 -- 旧 Planner / legacy Supervisor caller 显式构造纯文本 item 并留下迁移 TODO。 - -## 修改边界 - -- 允许修改:AGC shell 前端 `resourceReferences`、`App`、聊天队列、Direct Codex 相关测试和当前里程碑文档。 -- 不修改:Rust user item schema、附件 DTO、SpacetimeDB、HTTP API、用户已有 `.env` / `package-lock.json` 修改。 -- 不引入:`text` / `references` 到 canonical Direct Codex item 的任何兼容 fallback。 - -## 验证命令 - -- `npm run test -- apps/ai-game-creator-shell/tests/resourceReferences.test.ts apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx apps/ai-game-creator-shell/tests/chatPromptPolish.test.tsx apps/ai-game-creator-shell/tests/appSurface/project-conversation.suite.ts` -- `npm run ai-game-creator-shell:typecheck` -- `npm run check:encoding` -- `npm run check:doc-index` -- `git diff --check` - -## 风险与回滚点 - -- 空白 `input_text` 不再前端删除,需确保最终有效性判断只拒绝全空 content,不改变其它 part。 -- Direct caller 漏传 user item 时应在类型检查或明确错误分支暴露,不能静默重建。 -- 共享工作树含用户未提交修改;提交时只 stage 本计划和本次代码 hunk。 diff --git a/docs/project-memory/plans/【实施计划】DirectProject composer canonical content闭环-2026-09-21.md b/docs/project-memory/plans/【实施计划】DirectProject composer canonical content闭环-2026-09-21.md deleted file mode 100644 index 0fba5d3df..000000000 --- a/docs/project-memory/plans/【实施计划】DirectProject composer canonical content闭环-2026-09-21.md +++ /dev/null @@ -1,64 +0,0 @@ -# 【实施计划】DirectProject composer canonical content 闭环 - -| 字段 | 值 | -| --------- | --- | -| Milestone | `docs/project-memory/plans/【里程碑】DirectProject composer canonical content闭环-2026-09-21.md` | -| Status | implemented | -| Owner | Codex | - -## 交付结果 - -删除 Direct composer 的 `text + references` 回写事实源,改为完整 `content[]` 的单向读写;同时修复附件在 editor root 重建、润色回填和提交合并中的丢失窗口。Planning V2 / 快速编辑只保留明确的非 Direct adapter,不进入 Direct canonical 发送路径。 - -## 实施顺序 - -1. **锁定当前失败面**:补一个最小回归测试,先证明 `applyDraftToRoot` 对含 `agc_attachment_reference` 的 root 重建会丢附件,并记录 Direct 当前的三份并行状态与附件 sidecar 合并点。 -2. **收窄编辑器接口**:把 `ChatComposerDraft` 改成 content-only;将 `ResourceReferenceInput` 的受控恢复改为 `initialContent` / `content` 语义,删除 Direct 使用的 `value` + `references` 同步 effect。保留 `ChatReference` 仅用于 picker 节点创建和只读投影。 -3. **替换所有 root 写入**:删除 `buildDraftSegments` / `applyDraftToRoot` 的 Direct 调用;提供一个完整的 `applyContentToRoot`(或同等深模块接口),保留文本换写、引用和附件的顺序与字段。AI 润色改为“读取 content → 对回包文本按 token 扫描 → 原位换回真 part;被改写的 part 末尾补位”,引用与附件同一套口径。 -4. **收口 Direct controller**:以 `content[]` 作为草稿事实源;上传完成的附件在一个明确的 `append`/`merge` seam 合并,不再长期维护 `chatInput`、`chatReferences`、`chatContent` 三份状态。prompt 只在调用边界派生,队列和策略重试保留原 user item。 -5. **隔离非 Direct caller**:Planning V2 和资源快速编辑按各自需求选择 content-only 或独立文本 adapter;不得为了兼容它们把旧字段放回共享 Direct 接口。若快速编辑只需要文本,使用不承诺引用/附件语义的窄接口。 -6. **补齐验收证据并清理**:删除无调用方的旧 helper、字段和注释;更新测试 fixture、专题文档和本计划状态。完成后把稳定结论合并回功能说明/共享记忆,并删除已完成的临时计划。 - -## 重点修改边界 - -- `apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx` -- `apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts` -- `apps/ai-game-creator-shell/src/features/project-workspace/usePromptPolish.ts` / `chatPromptPolish.ts`(仅在需要支持 content 变换时) -- `apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts` -- `apps/ai-game-creator-shell/src/view/project-development/chat/components/DirectProjectComposer/` -- `apps/ai-game-creator-shell/src/view/project-development/planning/PlanningChatView.tsx` 与 `App.tsx` 中 Planning adapter -- `apps/ai-game-creator-shell/src/view/project-development/index.tsx` 的快速编辑输入 adapter -- 对应 `resourceReferences`、`resourceReferenceInput`、`chatPromptPolish`、Direct composer/appSurface 测试 - -## 关键不变量 - -- `content[]` 是唯一可发送事实;任何 `prompt`、label、chip 文案都是派生值。 -- `agc_attachment_reference` 不属于 `ChatReference`,不能借 `references` 传递。 -- 润色回包只按 token 反解析引用与附件(`draftScanToken` 与出站 `directCodexContentToPromptText` 同口径);token 被删掉时不猜位置,只把该 part 补在末尾,保证不丢。 -- Direct 初始首轮、普通提交、队列、权限确认重试都使用同一个 `DirectCodexUserItem` 语义。 - -## 验证命令 - -```bash -npm run test -- apps/ai-game-creator-shell/tests/resourceReferences.test.ts apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx apps/ai-game-creator-shell/tests/chatPromptPolish.test.tsx apps/ai-game-creator-shell/tests/appSurface/chat-composer.suite.ts apps/ai-game-creator-shell/tests/appSurface/project-conversation.suite.ts -npm run ai-game-creator-shell:typecheck -npm run check:encoding -npm run check:doc-index -git diff --check -``` - -## 风险与回滚点 - -- `ResourceReferenceInput` 当前同时服务 Direct、Planning、快速编辑;先建立 adapter seam,再删除旧 props,避免一次性把策划链路打坏。 -- 附件目前在 Direct controller 里作为待发 sidecar,若直接移入编辑器必须同步处理上传失败、移除、清空和项目切换;任何阶段都不能把附件只留在展示 chip 而未进入 user item。 -- 润色服务只返回文本,不能让其响应覆盖原 content;失败时保留原 content。回滚使用 Git revert,不增加运行时开关或兼容分支。 -- 工作树已有用户未提交修改,实施时只 stage 本里程碑涉及的 hunk。 - -## 落地结果 - -- 编辑器接口收窄为 content-only:`ResourceReferenceInput` 只接 `initialContent` / `onChange`,`ChatComposerDraft` 只剩 `content`;`applyDraftToRoot` 与受控 `value` / `references` 同步 effect 均删除。 -- 所有 root 写入统一走 `applyContentToRoot`;润色走 `applyPolishedTextToRoot`,对引用与附件做同一套 token 扫描并在原位置换回真 part,被改写的 part 末尾补位。 -- Direct controller 去掉 `chatInput` / `chatReferences` / `chatContent`,附件在提交边界合成进同一份 canonical content;Planning 与其它 legacy 消费方改用 `directCodexContentToLegacyContentDto` 单向取文本。 -- 删除无调用方的 `EMPTY_CHAT_COMPOSER_DRAFT`。 -- 回归证据:`resourceReferenceInput`(含附件 round-trip、润色原位恢复、润色末尾补位)、`resourceReferences`、`chatPromptPolish`、`usePromptPolish`、`resourceCanvasAssetGenerationReferences`、全量 `appSurface`、AGC typecheck、`check:encoding`、`git diff --check`。 -- 遗留 TODO:润色服务把 token 一起删掉时无法反推原位置;需要精确恢复时由产品补带位置信息的润色协议。 diff --git a/docs/project-memory/plans/【实施计划】DirectProject用户ResponseItem输入-2026-09-15.md b/docs/project-memory/plans/【实施计划】DirectProject用户ResponseItem输入-2026-09-15.md deleted file mode 100644 index f23267a84..000000000 --- a/docs/project-memory/plans/【实施计划】DirectProject用户ResponseItem输入-2026-09-15.md +++ /dev/null @@ -1,37 +0,0 @@ -# 【实施计划】DirectProject 用户 Response item 输入 - -| 字段 | 值 | -| --------- | ------------------------------------------------------------------------------------- | -| Milestone | `docs/project-memory/plans/【里程碑】DirectProject用户ResponseItem输入-2026-09-15.md` | -| Status | in-progress | -| Owner | Codex | - -## 修改边界 - -- 允许修改:AGC 壳 Rust agent 输入合同、DirectProject 历史适配、前端聊天引用模型、ts-rs 生成配置、当前聊天素材文档。 -- 明确不修改:assistant 返回协议、工具 activity、附件/图片上传 DTO、SpacetimeDB、HTTP API;上传 DTO 仅在入口转换为 canonical `content[]`,不再以 sidecar 文本追加。 -- 本切片明确:不根据 MIME 类型判断图片,不生成 `agc_image_reference`;所有上传文件统一映射为 `agc_attachment_reference`。 - -## 实现顺序 - -1. 提取深模块:Rust canonical user item 的定义、校验和 Codex wire 转换。 -2. 生成并接入 ts-rs 类型,排除生成文件 lint/style。 -3. 将前端 Lexical 草稿从 `text + references[]` 改为 inline content parts。 -4. 修改 Tauri command 与 DirectProject turn:校验通过后持久化 canonical item,再发送转换后的 Codex 输入。 -5. 删除本链路对 legacy conversation 行的读取 fallback,保留标准 `response_item`。 -6. 补齐定向测试与文档验证;每个独立切片形成小提交。 - -## 验证命令 - -1. `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml direct_codex` -2. 相关前端 Vitest 与类型检查。 -3. `npm run check:encoding` -4. `npm run check:doc-index` -5. `git diff --check` - -## 风险与回滚点 - -- ts-rs 生成路径或 workspace lint 配置不一致:先固定生成入口,再接入业务。 -- 历史中 canonical item 含 AGC part 时,thread replay 必须经过同一 wire converter;转换失败不得启动 turn。 -- 共享工作树存在用户 `.env` 修改,禁止覆盖或提交。 -- 每个切片保持独立提交,出现协议问题时按提交粒度回滚。 diff --git a/docs/project-memory/plans/【实施计划】DirectProject聊天模块抽离-2026-09-18.md b/docs/project-memory/plans/【实施计划】DirectProject聊天模块抽离-2026-09-18.md deleted file mode 100644 index fedc6feaf..000000000 --- a/docs/project-memory/plans/【实施计划】DirectProject聊天模块抽离-2026-09-18.md +++ /dev/null @@ -1,95 +0,0 @@ -# 【实施计划】DirectProject 聊天模块抽离 - -| 字段 | 值 | -| --------- | ----------------------------------------------------------------------------- | -| Milestone | `docs/project-memory/plans/【里程碑】DirectProject聊天模块抽离-2026-09-18.md` | -| Status | implemented | -| Owner | Codex | - -## 修改边界 - -### 允许修改 - -- `apps/ai-game-creator-shell/src/App.tsx`:删除 DirectProject 专属状态、ref、effect、订阅/历史/发送/队列/附件/中止处理和 Direct 专属 JSX 接线;保留项目开发工作台壳与 DirectProject / 立项策划两条入口的选择。 -- `apps/ai-game-creator-shell/src/view/project-development/chat/DirectProjectChatView.tsx`、`useDirectProjectChatController.ts` 与 `generated/`:新增 DirectProject 表现容器、controller 及其 ts-rs 契约目录;共享 reducer/分页/队列模块只引用这份 Direct 契约,不复制类型。 -- `view/project-development/chat/` 与 `view/project-development/planning/`:普通项目的对话归 `DirectProjectChatView`,Design Agent 与 Planning V2 归 `PlanningChatView`;行为中立的公共表现组件按需复用或抽出。 -- `DirectProjectSettingsDialog` 与 `ProjectDevelopmentView`:移除聊天侧钱包注入和聊天设置中的钱包行,在工作台布局头部/工具栏独立渲染钱包入口,保留账户入口功能。 -- 现有 DirectProject 测试文件:按新模块责任迁移 import、测试入口和 harness,不新增场景或断言集合。 -- 当前 ADR、里程碑和实施计划文档,以及必要的 `CONTEXT.md` 术语。 - -### 明确不修改 - -- Rust、Tauri 命令、共享 DTO、Thread Manager、Codex app-server 和 `.agent/conversations/project.jsonl` / 运行态事件合同。 -- DirectProject 的路由判定语义、模型配置语义、聊天投影规则、历史锚点与分页协议。 -- DirectProject、Design Agent、Planning V2 的正式行为与页面入口。 -- 任何运行时 feature flag、兼容别名、双跑路径或旧行为墓碑代码。 - -## 实现顺序 - -1. 以当前测试为基线,标记 DirectProject 断言归属:纯 reducer/投影/分页/附件测试归内部模块,Composer 的队列/恢复/中止断言归 Direct 容器 harness,项目开发页面只保留入口接线断言;不增加新测试场景。 -2. 建立 `direct-project-chat/` 私有模块边界,复用现有 `directThreadChat`、`directHistoryPaging`、`directHistoryAnchorGate`、`directTurnPresentation`、`chatComposerQueue` 与附件映射,不复制第二套事实源或 reducer。 -3. 将 DirectProject 生命周期整体搬入 `DirectProjectChat`:项目切换清理、订阅 bootstrap/notify/consume、首屏锚点、历史连拉、用户回合预写、Direct invoke、鉴权重试、FIFO 出队、附件上传、中止 released 分支和 manifest 刷新均由该容器管理。 -4. 将 Direct 专属 JSX 从工作台聊天宿主移入 Direct 表现模块:Direct 回合分区、运行中过程卡、Direct Composer、队列、附件、模型/推理选择、语音、中止、Direct 设置;共享组件只保留无行为真相的视觉表现。 -5. 项目开发工作台固定挂载 `DirectProjectChat`;立项策划(Design Agent、Planning V2)进入 `PlanningChatView`;删除 `directCodex` 作为共享组件行为开关及所有只服务它的 props,不保留 Direct fallback 或运行时 feature flag。 -6. 将钱包从聊天树移到 `ProjectDevelopmentView` 的工作台头部/工具栏:删除 `cloneElement` 对聊天元素的注入,删除 `DirectProjectSettingsDialog` 的钱包行和 Direct 上下文字段;钱包入口仍由布局直接渲染。 -7. 把现有测试按所有权迁移并运行定向验证;若发现行为差异,只修复抽离造成的回归,不扩展产品范围。完成后删除旧 Direct 分支与无 caller 的兼容代码。 - -## 测试迁移映射 - -| 现有测试 | 新归属 | -| --------------------------------------------------------------------------------------- | ------------------------------------------- | -| `directThreadChat.test.ts` | Direct 事件/历史状态模块 | -| `directHistoryPaging.test.ts` | Direct 历史分页模块 | -| `directHistoryAnchorGate.test.ts` | Direct 订阅锚点模块 | -| `directTurnPresentation.test.ts` | Direct 聊天投影表现模块 | -| `directCodexTurnAttachments.test.ts` | Direct 附件模块 | -| `chat-composer.suite.ts` 的 FIFO、恢复出队、终止与竞态用例 | Direct 容器/发送队列 harness | -| `project-development.suite.ts` 的 Direct 入口、历史、工具卡片、运行态隔离和连续回合用例 | Direct 容器接线;仅迁移测试入口,不新增场景 | - -## 验证命令 - -1. `npx vitest run apps/ai-game-creator-shell/tests/directThreadChat.test.ts apps/ai-game-creator-shell/tests/directHistoryPaging.test.ts apps/ai-game-creator-shell/tests/directHistoryAnchorGate.test.ts apps/ai-game-creator-shell/tests/directTurnPresentation.test.ts apps/ai-game-creator-shell/tests/directCodexTurnAttachments.test.ts` -2. `npx vitest run apps/ai-game-creator-shell/tests/appSurface/chat-composer.suite.ts apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts` -3. `npx tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit` -4. `npm run check:doc-index` -5. `npm run check:encoding` -6. `git diff --check` - -## 风险与回滚点 - -- **状态遗漏**:任何 Direct 专属 state/ref/effect 留在 `App.tsx` 都会形成双重所有权;以 `rg` 扫描 Direct 专属符号和 `directCodex` props 作为删除检查。 -- **事实源漂移**:不得在新容器里重新维护 messages、turn-stream 或 tool-calls 副本;继续只使用项目对话历史、运行态事件和聊天投影。 -- **竞态回归**:重点检查 subscribe 回执前 notify 欠账、首屏锚点闸门、`turn.completed` 与 invoke finally 的 FIFO 出队窗口、提交早于 `turn.started` 的中止以及项目切换时附件/队列清理。 -- **布局回归**:钱包必须在工作台布局头部/工具栏出现,且聊天设置不再包含钱包行;账户入口功能不能因聊天抽离丢失。 -- **回滚**:本次采用一次性替换;失败时整体 Git revert,不保留旧/新双路径或运行时 fallback。 - -## 实施记录(2026-09-19) - -### 模块落位 - -`apps/ai-game-creator-shell/src/view/project-development/chat/` 最终结构: - -| 目录 | 内容 | -| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `DirectProjectChatView.tsx` | 唯一公开入口:项目路径、入口首轮需求、两条权限门,以及对壳的 `announce` 句柄 | -| `components/` | 表现层,一个组件一个目录、逻辑与组件同目录:`DirectProjectChatHeader/`、`DirectProjectComposer/`(含 `ComposerControls.tsx`、`chatComposerQueue.ts`、`chatComposerVoice.ts`)、`DirectProjectConversation/`(含 `DirectProjectTurn.tsx`)、`DirectProjectSettingsDialog/`、`ToolCallGroup/`(含 `toolCallGroupPresentation.ts`) | -| `controller/` | `useDirectProjectChatController`(发送/队列/附件/中止/历史分页)、`useDirectProjectManifest`(清单与 `projectId` 订阅)、`useDirectThreadChatSubscription`(`subscribe → consume → notify` 单飞循环 + 聊天 reducer 状态) | -| `conversation/` | `directThreadChat.ts`(reducer)、`directThreadItemProjection.ts`、`directTurnPresentation.ts`、`directCodexConversation.ts`、`directCodexSession.ts`、`directCodexTurnAttachments.ts` | -| `history/` | `directHistoryPaging.ts`、`directHistoryAnchorGate.ts` | -| `generated/` | Rust ts-rs 导出的 Direct 契约 | - -### 关键取舍 - -- 线程订阅与聊天 reducer 状态从控制器里提成独立 hook `useDirectThreadChatSubscription`:运行态事实源只有它一份,控制器只读投影结果,历史分页仍并入同一个 reducer。 -- 工作台级动作(如 `game.run_local` 的预览结果)不再写 `App.tsx` 的 `messages`:壳通过 `DirectProjectChatHandle.announce` 把这句话交给聊天的本地消息流,壳不持有 Direct 聊天消息。 - -### 验证结果 - -- `npx vitest run` 五个 Direct 纯模块测试:40 通过。 -- `npx vitest run apps/ai-game-creator-shell/tests/appSurface.test.ts -t "direct"`:15 通过 / 4 失败,且 4 条在本次改动前(`HEAD` 的 `/tmp` worktree 基线)同样失败(用例期望 `chat_with_game_creator_direct_codex` 被调用,但 harness 未桩 `read_game_creator_app_config`,模型可用性校验把提交挡在 invoke 之前;另两条是既有交互断言)。基线同口径为 14 通过 / 5 失败,本次净增 1 条通过。 -- `npx vitest run apps/ai-game-creator-shell/tests/appSurface.test.ts` 全量:153 失败 / 307 通过 / 17 跳过;`HEAD` 基线同口径 155 失败 / 305 通过。 -- `npx tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit`、`npx eslint --ext .ts,.tsx`、`npx prettier --check` 通过。 - -### 本计划外的后续项 - -- Supervisor 前端链路已随本计划之后的变更整体退役(Supervisor 独立调试窗口、纯聊天容器、工作台壳的 Supervisor 运行态与专业 Agent 面板、`App.tsx` 里只服务它们的 state/ref/effect/handler 全部删除),项目对话只保留 DirectProject 与立项策划两条产品路径;见 [decision-log](../shared-memory/decision-log.md) 2026-09-19 条。 diff --git a/docs/project-memory/plans/【实施计划】DirectProject聊天真相源收敛-2026-09-16.md b/docs/project-memory/plans/【实施计划】DirectProject聊天真相源收敛-2026-09-16.md index 497e6842c..50a4811ea 100644 --- a/docs/project-memory/plans/【实施计划】DirectProject聊天真相源收敛-2026-09-16.md +++ b/docs/project-memory/plans/【实施计划】DirectProject聊天真相源收敛-2026-09-16.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --------- | ------------------------------------------------------------------------------- | | Milestone | `docs/project-memory/plans/【里程碑】DirectProject聊天真相源收敛-2026-09-16.md` | -| Status | implemented | +| Status | implemented-awaiting-runtime-acceptance | | Owner | Codex | ## 修改边界 diff --git a/docs/project-memory/plans/【实施计划】Direct三维请求自选技术栈-2026-09-16.md b/docs/project-memory/plans/【实施计划】Direct三维请求自选技术栈-2026-09-16.md index 1caba8de9..a6e0a4f88 100644 --- a/docs/project-memory/plans/【实施计划】Direct三维请求自选技术栈-2026-09-16.md +++ b/docs/project-memory/plans/【实施计划】Direct三维请求自选技术栈-2026-09-16.md @@ -1,5 +1,5 @@ Version: 1.0 -Status: implemented; real-project runtime smoke pending +Status: implemented-awaiting-runtime-acceptance(真实项目 runtime smoke 待补) Date: 2026-09-16 Parent Milestone: docs/project-memory/plans/【里程碑】Direct三维请求自选技术栈-2026-09-16.md diff --git a/docs/project-memory/plans/【实施计划】Direct回合跨页面生命周期与运行中项目可见性-2026-09-15.md b/docs/project-memory/plans/【实施计划】Direct回合跨页面生命周期与运行中项目可见性-2026-09-15.md index 5f7b34bcf..52b451442 100644 --- a/docs/project-memory/plans/【实施计划】Direct回合跨页面生命周期与运行中项目可见性-2026-09-15.md +++ b/docs/project-memory/plans/【实施计划】Direct回合跨页面生命周期与运行中项目可见性-2026-09-15.md @@ -1,7 +1,7 @@ # 【实施计划】Direct回合跨页面生命周期与运行中项目可见性-2026-09-15 Version: 1 -Status: in-progress +Status: implemented-awaiting-runtime-acceptance Date: 2026-09-15 Milestone: `【里程碑】Direct回合跨页面生命周期与运行中项目可见性-2026-09-15.md` @@ -49,3 +49,13 @@ Milestone: `【里程碑】Direct回合跨页面生命周期与运行中项目 - 忙碌态恢复不得与既有 `chatAgentBusy` 的失败清理互相覆盖;出现卡死忙碌态时优先回滚重连,不影响身份锁与后台回合本体。 - 面板若在窄窗口挤压主内容,先按既有响应式约定隐藏面板,不改主布局。 - 报错归类修正若与既有断言冲突,先确认断言锁的是“正确行为”还是历史错误文案,再决定改断言还是改实现。 + +## 本轮验证(2026-09-24) + +- Rust 定向:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 direct_active_turn` → `read_direct_active_turn_reports_the_registered_turn_and_disappears_after_drop` 通过(登记可见、guard drop 后消失)。 +- 前端定向:`npx vitest run tests/directActiveTurns.test.tsx tests/agentRuntimeModel.test.ts` → 29 passed(快照读取、单飞刷新、事件订阅、失败保留、报错归类)。 +- 全量界面门禁(含 appSurface):`npm run ai-game-creator-shell:check:web` → 185 files passed / 1 skipped,1806 tests passed。 +- 计划里写的「快照轮询」没有留在产品运行时:`src/features/agent-runtime/directActiveTurns.ts` 走 `DIRECT_ACTIVE_TURNS_CHANGED_EVENT` 事件唤醒 + 单飞读取,事件桥不可用时只做一次启动快照,不恢复定时轮询。 +- 仍未取得证据(需要真实运行):真机重新进入正在跑的项目后恢复忙碌态与进度、标题栏入口点击进入对应项目、回合结束后可再次发送。 + +因此本计划从 `in-progress` 改为 `implemented-awaiting-runtime-acceptance`:代码与定向测试已落地,缺的是真机运行时证据。 diff --git a/docs/project-memory/plans/【实施计划】UI设计文档引用代码上下文-2026-09-14.md b/docs/project-memory/plans/【实施计划】UI设计文档引用代码上下文-2026-09-14.md index f0a4d6331..fd123a6ef 100644 --- a/docs/project-memory/plans/【实施计划】UI设计文档引用代码上下文-2026-09-14.md +++ b/docs/project-memory/plans/【实施计划】UI设计文档引用代码上下文-2026-09-14.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Version | 1 | -| Status | ready | +| Status | implemented-awaiting-runtime-acceptance | | Owner | Codex | | Milestone | `docs/project-memory/plans/【里程碑】UI设计文档引用代码上下文-2026-09-14.md` | @@ -49,3 +49,10 @@ - `generate_ui_design_code_at` 会持有项目写锁;多引用必须顺序调用,不能并行写同一项目。 - 生成失败继续发送是已确认语义;测试必须证明错误文本进入 prompt 而不是被转成聊天失败。 - 若发现生产者仍写入旧 `UI`,按开发阶段合同直接修生产者和 fixture,不增加运行时兼容分支。 + +## 本轮复核(2026-09-24) + +- 身份与词表已落地:`server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs` 有 `UiDesignDoc => "ui-design-doc"`,生成的 TS union 同步包含 `ui-design-doc`;旧 `UI` / `ui` / `ui-design` 没有解析入口,也没有兼容 fallback。 +- 代码上下文注入已落地:`agent/direct_codex_user_item/wire.rs` 命中 `ui-design-doc` + `application/json` 时调用 `generate_ui_design_code_at`,成功追加生成代码路径、失败追加原始生成错误,其它引用不受影响;决策记录见 `decision-log.md` 的 2026-09-14 与 `ui-design-doc` 词表条目。 +- 定向测试(本轮实跑):`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 direct_codex_user_item::` → **33 passed / 0 failed**,含生成代码路径注入与「生成代码遇到错误」两条断言。 +- 未验证(需要真实 Provider 回合):在真实 Direct Codex 回合里引用 UI JSON 文档后,模型确实按注入的生成代码路径工作。 diff --git a/docs/project-memory/plans/【实施计划】后台模板上传-2026-09-21.md b/docs/project-memory/plans/【实施计划】后台模板上传-2026-09-21.md index 1a3a1b1df..5ae0d6c00 100644 --- a/docs/project-memory/plans/【实施计划】后台模板上传-2026-09-21.md +++ b/docs/project-memory/plans/【实施计划】后台模板上传-2026-09-21.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Version | 1.0 | -| Status | in-progress | +| Status | implemented-awaiting-runtime-acceptance | | Date | 2026-09-21 | | Milestone Spec | `docs/project-memory/plans/【里程碑】后台模板上传-2026-09-21.md` | @@ -38,3 +38,12 @@ git diff --check - **风险:大文件内存**。ZIP(≤64 MiB)与封面在内存中校验,单批上限 20;需要更大模板时走 CLI。 - **风险:批量部分写入**。所有对象在清单提交前写入且不删除;中途失败时清单不变、已写对象成为未被引用的历史对象,由后续同键复用。 - **回退**:下线路由与页面入口即可停止使用;已发布内容按既有 CLI / 后台下架流程处理,历史对象保留。 + +## 本轮验证(2026-09-24) + +- `cargo test --locked -p module-assets --manifest-path server-rs/Cargo.toml -- template_library`:**11 passed**(清单合并、未知字段保留、下架状态、标识符与相对路径校验)。 +- `cargo test --locked -p api-server --manifest-path server-rs/Cargo.toml -- agc_template`:`agc_template_routes_require_the_template_tab_permission` 通过(无 `agc-templates` 页签权限不可读写)。 +- `npm run admin-web:typecheck`:通过。 +- `npx vitest run apps/admin-web/src/pages/AdminAgcTemplatesPage.test.tsx apps/admin-web/src/api/adminApiClient.test.ts`:2 文件 / **36 passed**。 +- 修掉一个真实缺陷:上传弹窗的表头把 `TableHeader`(渲染 ``)当列头单元格用,DOM 实际是 `…`,列头语义与 `genarrative-ui-table__head` 样式一起丢失(jsdom 报 ` cannot contain a nested
`)。已改为 `TableHeader > TableRow > TableHead`,并先写失败回归钉住列头角色与层级;修复前该用例红、修复后绿。 +- 仍未执行:dev bucket 的真实导入写入 smoke(发布不可逆,需要用户显式确认)。 diff --git a/docs/project-memory/plans/【实施计划】图集切片模式显式决策-2026-09-17.md b/docs/project-memory/plans/【实施计划】图集切片模式显式决策-2026-09-17.md index 3135990bb..7335a96ab 100644 --- a/docs/project-memory/plans/【实施计划】图集切片模式显式决策-2026-09-17.md +++ b/docs/project-memory/plans/【实施计划】图集切片模式显式决策-2026-09-17.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --------- | ------------------------------------------------------------------------ | | Milestone | `docs/project-memory/plans/【里程碑】图集切片模式显式决策-2026-09-17.md` | -| Status | ready | +| Status | implemented-awaiting-runtime-acceptance | | Owner | Codex | ## 修改边界 @@ -37,3 +37,14 @@ - 风险 1:已发布的 AGC 客户端与第三方外部 API 调用方在未更新前会因缺失 `sliceMode` 收到 `400`。回滚点为「恢复服务端兜底读取连通域」,但该兜底与本次里程碑目标冲突,需产品确认后再引入过渡期。 - 风险 2:AGC 原生工具 schema 从“可选”改为“显式声明”,自主运行时可能出现一轮可修复的工具参数失败。回滚点为「保留 schema 字段但收回 description 中的强制措辞」。 - 风险 3:画板前端显式声明模式后,画板自身不再具备网格生成能力;需要网格时改用外部 API 或后续单独开放画板入口。 + +## 本轮复核(2026-09-24) + +状态原为 `proposed` / `ready`(规范态),实现已经落地,本轮逐条核对并改记为 `implemented-awaiting-runtime-acceptance`: + +- 验收 1/2/6(缺失、空白、未知取值、模式与网格矛盾在副作用前 400 且带 `field=sliceMode`):`cargo test -p api-server slice_mode` → `slice_mode_must_be_declared_and_accepts_explicit_modes` 通过,断言 `400`、`field=sliceMode` 与「没有默认值 / grid / connected-components」的可执行文案;`cargo test -p api-server grid_dimensions_reject_more_than_maximum_output_slices` 通过。 +- 验收 3(公开契约、MCP / Agent 说明、Skill、画板前端都不再声明默认值):`docs/openapi/genarrative-external-v1.openapi.json` 的请求体 `required` 含 `sliceMode` 且响应回显同一字段;`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 tool_catalog_preserves_reviewed_resource_contracts` 通过(`sliceMode` 必填、无默认值、说明含决策要求);`.codex/skills/genarrative-external-editor-api` 与客户端技能包 `taonier-art-assets` 都写明「没有默认值」与两种模式的取舍。 +- 验收 4(自有调用方显式声明):`agent/direct_tool_bridge.rs` 在图集分支强制 `sliceMode` 并拒绝矛盾参数;`commands.rs` 与 `agent/direct_runtime/mod.rs` 按 kind 显式传入模式(标准美术包另带 `sliceCount=4`)。 +- 验收 7(标准美术包四张切片):`agent/direct_runtime/mod.rs` 对 `icon-spritesheet` 显式声明 `connected-components` + `sliceCount=4`,`tests/project.rs` 断言落盘含 `"sliceCount":4`,结果不是四张时失败关闭。 +- 前端:`npx vitest run src/services/image-editor/editorProjectClient.test.ts` → **62 passed**(含 grid 缺维度、connected-components 带网格尺寸两条拒绝路径)。 +- 仍未验证(需要真实环境):本地 `api-server` 缺字段请求的运行时 smoke(需要登录态与本地 SpacetimeDB)、真实平台图集生成返回四张切片的端到端结果。 diff --git a/docs/project-memory/plans/【实施计划】多选素材批量标签-2026-09-17.md b/docs/project-memory/plans/【实施计划】多选素材批量标签-2026-09-17.md index f89175d32..7d4aa888a 100644 --- a/docs/project-memory/plans/【实施计划】多选素材批量标签-2026-09-17.md +++ b/docs/project-memory/plans/【实施计划】多选素材批量标签-2026-09-17.md @@ -32,3 +32,10 @@ ## 下一验收入口 在已登记素材上分别从画布多选工具栏与资源面板进入批量标签,确认新增标签、原标签保留、刷新后持久化与跨项目切换。真实客户端验收通过后,将持久行为保留在主规范,删除本实施计划与里程碑;远程推送与 CI 等用户恢复安排,不自行启动。 + +## 本轮复验(2026-09-24) + +- 前端集成与模型:`npx vitest run tests/resourceBatchTagsIntegration.test.tsx tests/resourceBatchTagTargetModel.test.ts --root apps/ai-game-creator-shell` → **9 + 2 passed**(画布与资源面板两条入口、混合选择禁用、部分失败不留半写、切项目丢弃迟到回包、manifest 回读失败仍报「已保存但刷新失败」)。 +- 原生:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 batch_tag` → **12 passed**(追加保留原标签与分类、去重与上限、no-op 不写审计不推进 revision、审计失败回报已写入整批、缺目标不写、权限门面、未知字段拒绝、CAS 与项目身份)。 +- 顺带修掉一个测试可运行性缺陷:`resourceBatchTagsIntegration.test.tsx` 与 `resourceTagStatsRefresh.test.tsx` 用 `describe` / `it` 却没有导入(194 个 AGC 测试文件里只有这两个这样写),因此按仓库常见的 `--root apps/ai-game-creator-shell` 口径执行时会以 `ReferenceError: describe is not defined` 整文件失败;已按同目录套件惯例从 `./appSurface/harness` 显式导入,两种执行口径现在都能跑。 +- 仍未验收(需要真实客户端):在已登记素材上从画布多选工具栏与资源面板进入批量标签,确认新增标签、原标签保留、刷新后持久化与跨项目切换。 diff --git a/docs/project-memory/plans/【实施计划】对话回合唯一投影-2026-09-16.md b/docs/project-memory/plans/【实施计划】对话回合唯一投影-2026-09-16.md deleted file mode 100644 index c22852aec..000000000 --- a/docs/project-memory/plans/【实施计划】对话回合唯一投影-2026-09-16.md +++ /dev/null @@ -1,12 +0,0 @@ -# 对话回合唯一投影实施计划 - -对应:[对话回合唯一投影](./【里程碑】对话回合唯一投影-2026-09-16.md)。 - -本次增量顺序:先移除 Provider 回放对活动 client 回合的写入,复用活动快照同步并处理过期异步结果;再为历史信封及切片增加可选时间映射;最后在现有回合投影中分离最终回复和可折叠过程,复用 details 与工具组件。新增恢复、时间、折叠边界用例,只运行静态检查,不运行测试;按最新授权本地提交,不推送。 - -1. 前端抽取纯回合呈现投影,完整历史关联后分页;删除旧的消息锚定/实时/未归属独立渲染分支。 -2. Rust 按 item 完成边界冲刷,段切换返回全部快照;收尾等待写任务,修正 upsert 与跨回合裁剪。 -3. 核对 MCP 输入输出与同状态更新,保留现有脱敏。 -4. 自审正常、失败、历史无流、分页和重复快照路径;只执行定向 tsc、cargo check、check:encoding、check:doc-index 与 git diff --check,不运行测试;按最新授权提交到本地,不推送。 - -风险:旧流可能只有前缀或部分回合;只依据原始 item 身份补齐,不能靠长度比例推断。实机须重启 Rust 客户端后验收。回滚只撤销本次触及的实现片段,保留工作树原有样式和输入输出修改,不改用户项目数据。 diff --git a/docs/project-memory/plans/【实施计划】对话总耗时与动态工具计时-2026-09-18.md b/docs/project-memory/plans/【实施计划】对话总耗时与动态工具计时-2026-09-18.md index 3a8bd8fe1..757411baf 100644 --- a/docs/project-memory/plans/【实施计划】对话总耗时与动态工具计时-2026-09-18.md +++ b/docs/project-memory/plans/【实施计划】对话总耗时与动态工具计时-2026-09-18.md @@ -49,3 +49,9 @@ 已完成同身份发送时间保留、原生 userItemId 关联、live 为空或终态先于历史时的精确回填;旧回合终态及取消回包不能关闭另一条已知身份的新请求。计时 40 项定向、appSurface 462 项(17 跳过)通过,原生身份序列化/重放/取消用例 3 项及原阶段时间序列化 1 项通过;绑定由 ts-rs 导出,Rust all-targets locked offline check 通过。 Edge 真实浏览器使用生产 reducer/组件和模拟原生事件,确认发送后的 8 秒启动等待计入总耗时、100ms 递增及终态冻结;仅历史恢复、live 为空的回合显示正确的 2.0 秒。真实 Provider 与原生客户端端到端尚未验证,不据本地通过宣称远程 CI 或发布通过。 + +## 本轮复验(2026-09-24) + +- 纯计时投影:`npx vitest run tests/elapsedDuration.test.ts tests/directTurnPresentation.test.ts --root apps/ai-game-creator-shell` → **16 + 17 passed**(未知/缺失/倒序边界的隐藏口径、整轮与工具组分别取时)。 +- 工具组与界面链路(含前组冻结、后组运行、并行、重试清空、迟到回合等):由 `npm run ai-game-creator-shell:check:web` 全量执行 → 185 files / 1808 passed / 14 skipped;仓库根 `npm test` → 416 files / 4391 passed / 26 skipped。 +- 仍未验证(需要真实客户端 + 真实 Provider):8 秒启动等待计入总耗时、100ms 递增与终态冻结在原生事件下的表现;本轮只有模拟原生事件与 jsdom 证据。 diff --git a/docs/project-memory/plans/【实施计划】平台会话身份与凭据分离-2026-09-16.md b/docs/project-memory/plans/【实施计划】平台会话身份与凭据分离-2026-09-16.md deleted file mode 100644 index ef86f0b07..000000000 --- a/docs/project-memory/plans/【实施计划】平台会话身份与凭据分离-2026-09-16.md +++ /dev/null @@ -1,47 +0,0 @@ -# 【实施计划】平台会话身份与凭据分离 - -| 字段 | 值 | -| --------- | -------------------------------------------------------------------------- | -| Milestone | `docs/project-memory/plans/【里程碑】平台会话身份与凭据分离-2026-09-16.md` | -| Status | done(待验收复核) | -| Owner | Codex | - -## 修改边界 - -- 允许修改:`apps/ai-game-creator-shell/src-tauri/src/platform_session.rs`、`commands.rs`、`runner/`(attach 参数与安装路径)、`project/external_editor_bindings.rs`、`project/resource_editor.rs`、`agent/generation/canvas_generation.rs`、`agent/direct_tools_mcp.rs`、`agent/direct_runtime/`、`assets.rs` 中与身份判据相关的调用点。 -- 允许修改:`apps/ai-game-creator-shell/src/services/platformSession.ts`、`clientAuth.ts`、`clientApi.ts`、`src/App.tsx` 及对应测试。 -- 允许修改:`src/services/apiClient.ts` 刷新收敛重试与对应测试。 -- 允许修改:`server-rs/crates/api-server/src/refresh_session.rs`、`auth_session.rs` 与对应测试。 -- 明确不修改:`/api/external/v1` 路由与 OpenAPI、`refresh_session` schema / 迁移 / 绑定、生成账本与计费、Provider 与 MCP 工具边界。 - -## 实现顺序 - -1. 原生会话状态拆分:`PlatformSessionSnapshot` 增加身份代次,`generation` 更名并明确为写入 revision;安装 / 清除 / 冻结校验按新判据重写,补单元用例。 -2. 逐个修正原生调用点(binding、生成 operation、MCP 会话、diagnostics、Runner attach),由编译器定位所有旧判据读取点。 -3. renderer:身份代次与 native revision 分离,续期走凭据更新路径;刷新失败只在权威失效时清会话;补前端用例。 -4. 刷新收敛:AGC 与网站前端在刷新 401 时用当前 cookie 重试一次。 -5. `api-server`:轮换失败不再下发清 cookie 响应,补定向用例。 -6. 回写主规范与共享记忆,删除临时计划。 - -## 验证命令 - -1. `npm run ai-game-creator-shell:check:rust`(或定向 `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml platform_session`) -2. `npm --prefix apps/ai-game-creator-shell test -- src` 对应前端定向用例 -3. `npm run test -- src/services/apiClient.test.ts` -4. `cargo test -p api-server refresh_session --manifest-path server-rs/Cargo.toml` -5. `npm run typecheck`、`npm run check:encoding`、`git diff --check` - -## 风险与回滚点 - -- 风险:身份代次判据改宽后,若换号路径仍复用旧代次,旧账号请求可能带着新账号 token 发出。缓解:换号、退出和 origin 变化必须先推进身份代次;Rust 侧对同代次不同主体的写入失败关闭,并用用例覆盖。 -- 风险:revision 与身份代次混用会让迟到写入复活旧会话。缓解:写入顺序只认 revision,身份只认身份代次,两者分别有用例。 -- 回滚点:先回滚 renderer 的续期路径与原生判据(第 1-3 步),再回滚服务端响应语义(第 5 步);`refresh_session` schema 不在本次改动内,无需数据回滚。 - -## 执行结果 - -1. `platform_session.rs`:`PlatformSessionSnapshot` 拆成 `identity_generation` + `revision`,新增 `PlatformSessionIdentity`、身份租约与 `validate_frozen_platform_session`;安装 / 清除按"revision 排序 + 身份归属"双判据实现。 -2. 原生调用点:`external_editor_bindings.rs`、`resource_editor.rs`、`canvas_generation.rs`、`direct_tools_mcp.rs`、`direct_runtime`、`assets.rs`、`commands.rs` 全部改按身份判定;`commands.rs` 的 IPC 改为 `install_platform_account_session(userId, accessToken, apiBaseUrl, identityGeneration, revision)`、`clear_platform_account_session(identityGeneration, revision)`、`read_platform_account_session_state()`。 -3. Runner:attach 参数新增 `platform_auth_revision`,`platform_auth_generation` 只表达身份代次;`remember_*` / `validate_*` 按 revision 排序、按身份归属判定。 -4. renderer:`platformSession.ts` 拆分 `platformNativeIdentityGeneration` 与 `platformNativeRevision`,续期走 `commitPlatformCredentialRefresh`(不推进身份代次);刷新失败结果新增 `authoritative`,`AuthenticatedClient` 只在权威失效时登出。 -5. 刷新收敛:AGC `clientAuth.refreshClientAuthAccessToken` 与网站 `apiClient.refreshAccessToken` 在 401 后用当前 cookie 再试一次;网站侧额外要求本代次仍是当前代次。 -6. `api-server`:`refresh_session` 失败不再下发清 cookie 响应(`map_refresh_error_with_clear_cookie` 删除),并更新两条 `app::tests` 断言。 diff --git a/docs/project-memory/plans/【实施计划】引用粘贴解析-2026-09-22.md b/docs/project-memory/plans/【实施计划】引用粘贴解析-2026-09-22.md deleted file mode 100644 index c90010981..000000000 --- a/docs/project-memory/plans/【实施计划】引用粘贴解析-2026-09-22.md +++ /dev/null @@ -1,63 +0,0 @@ -# 引用粘贴解析实施计划 - -对应:[引用候选由宿主注入](../../adr/【ADR】引用候选由宿主注入-2026-09-22.md)(含 2026-09-22 修订节);决策记录见 `docs/project-memory/shared-memory/decision-log.md` 的 2026-09-22 条目。上一步的重构计划见 [引用输入区重构与宿主注入](【实施计划】引用输入区重构与宿主注入-2026-09-22.md),那份明确不含本项。 - -## 一句话交付与验收判据 - -把从用户消息气泡(或任何同口径文本)复制出来的 `@显示名` / `$名称` 粘贴进引用输入区时,原位重建同顺序的引用芯片;其余文字逐字保留。 - -验收判据: - -1. 粘贴文本 → 引用:`@显示名` 与 `$名称` 逐字命中当前宿主注入的 provider 候选时原位换成芯片,一次 Ctrl+Z 整体回退,token 之外的每个字符(含换行与空白)原样保留。 -2. 逐字一致、不做兼容别名:不认 `@hero.png`、`resourceId`、大小写变体、全角 `@`;token 前后必须是行首 / 行尾或空白。 -3. 宁可不成芯片也不能认错:同名多候选(同一个 token 对应多条引用身份)一律按文本保留;未命中的 token 静默保留,不提示、不猜路径或文件名。 -4. 只有真的解析出引用时才接管:同 namespace 的 `application/x-lexical-editor` 负载、不含 token 的纯文本、图片文件粘贴一律放行编辑器默认导入,现有粘贴行为逐字不变。 -5. 附件与运行画面区域不参与粘贴解析(静默 provider 没有候选),它们的 token 粘贴时按文本保留。 -6. Skill 目录冷启动不阻塞粘贴:`lookup()` 是纯函数,目录没到就是空数组——冷启动时粘贴 `$名称` 保留为文本(不等待、不补读),用户敲过一次 `$` 后即可解析。 - -## 流程判定 - -本次是共享组件的一处行为增量 + provider 契约加两个可选能力,不动 schema、不动公开 API/DTO、不动后端;按轻量流程只建本实施计划,不新建主规范与里程碑规范(与上一步重构同一判定)。 - -## 提交切分 - -1. **反解析口径**:`resourceReferences.ts` 新增 `buildContentFromPastedText(text, references)`(粘贴侧唯一反解析;与 `buildContentFromTextTokens` 同一套边界规则),配规则矩阵单测。 -2. **provider 契约**:`reference-source/types.ts` 把菜单查询改名为 `fuzzyLookup(query)`、新增精确查找 `lookup()`(两者共用同一份候选来源);`resourceReferenceProvider` 给全量可提及候选,`skillReferenceProvider` 给去重后的 Skill 候选。 -3. **输入区接管**:`ResourceReferenceInput` 注册 `COMMAND_PRIORITY_CRITICAL` 的 `PASTE_COMMAND`,只在解析出引用时 `preventDefault` 并在一次 `editor.update`(`PASTE_TAG`)内按选区插入;配集成用例。 -4. **文档**:`CONTEXT.md` 术语、本计划、ADR 修订节、`docs/【功能说明】AGC聊天素材引用-2026-09-08.md` 与决策记录。 - -## 验证 - -定向:`npx vitest run apps/ai-game-creator-shell/tests/resourceReferences.test.ts apps/ai-game-creator-shell/tests/referenceSourceProviders.test.ts apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx`;全量:`npm run typecheck`、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check`。真实客户端手感(粘贴时的候选菜单位置、大段文本粘贴观感、Tauri 剪贴板只带图片时的行为)留待真机验收。 - -## 风险与回滚 - -- 解析接管会绕过 Lexical 的 `text/html` 富文本导入:只在文本里真的解析出引用时接管,取舍已在上一条判据里限定;要完全避开富文本场景可以后续按 `clipboardData.types` 再收窄。 -- 气泡里若出现与素材同名的 `@区域标签` / `@附件名`,粘贴会被认成素材引用——纯文本无法区分,属已知取舍。 -- 回滚按提交粒度 revert;canonical content 形状、provider 的既有能力与出站文本口径都不变。 - -## 执行状态(2026-09-22) - -已完成:`buildContentFromPastedText` 与规则矩阵单测(命中 / 未命中 / 相邻中文 / 扩展名 / 大小写 / 全角 / 同名歧义 / 重复出现 / 换行 / 与显示口径互为逆运算);provider 的 `fuzzyLookup` / `lookup` 及用例;输入区 `PASTE_COMMAND` 接管与 5 条集成用例(粘贴重建芯片、未命中保持字面、纯文本走默认导入、Lexical 负载让位、Skill 冷启动保持字面且敲过 `$` 后可解析);文档同步。 - -未做(本次范围外):斜杠命令 `/` 解析、拖拽文本(drop)、附件 / 运行画面区域 / 文件路径 / URL / 剪贴板图片的解析、复制侧 `text/plain` 形态调整、扩展安装卸载后的目录即时失效。 - -## 追加执行状态(2026-09-23):前缀重叠按「引用名无空白」收口 - -自动评审留下的唯一破坏性项(`@hero` 与 `@hero v2` 互为前缀时粘贴会多插一枚短名芯片)不改反解析,改为把不变量前移到引用名: - -- `resourceReferences.ts` 新增共享 `normalizeMentionName(value)`(内部空白折 `-`、裁首尾),素材显示名(`resourceDisplayName`)、Skill 名(目录读入与 `toReference` / `mentionToken`)、附件名(导入映射与 `toReference` / `mentionToken`)与两个 token 投影(`chatReferenceMentionToken`、`directCodexContentToPromptText`)统一过这一份;token 层重复归一化是幂等的。 -- 名称里不做 `resourceId` 兜底这一条按评审校正:词干为空(`.env` / `.gitignore` 这类整名就是扩展名的文件)时 `resourceDisplayName` 回退 `asset.id`,回退值同样过 `normalizeMentionName`;`normalizeMentionName` 自己仍只做归一化。 -- 代价与取舍:`hero v2` 与 `hero-v2` 归一化后同名时走既有的「同名多候选按文本保留」;改动前生成的旧文本里的 `@hero v2` 不再解析。 -- 验证:`normalizeMentionName` / 显示名 / token 口径单测 + 前缀重叠回归用例(归一化后粘贴只剩正确的那一枚芯片)+ provider 两处用例;把 `normalizeMentionName` 变异成恒等后新增用例全红。 - -## 追加执行状态(2026-09-23 第二轮自动评审):空名字与插入兜底收口 - -第二轮自动评审的四个问题逐个提交处理,落点都在 `apps/ai-game-creator-shell`: - -- 显示名不再可能为空:`resourceDisplayName` 在文件名词干为空(`.env` / `.gitignore`)时回退 `asset.id`,回退值同样过 `normalizeMentionName`(提交 `4e90465c4`)。这条校正了上一节「不做兜底」的写法,决策记录与功能说明同步。 -- 粘贴解析跳过退化 token:`buildContentFromPastedText` 组装候选时跳过 `token.length <= 1` 的条目,裸 `@` / `$` 不再认领正文里的触发符(提交 `3f9c698a6`)。 -- 粘贴接管改成「插入真的发生之后」才 `preventDefault`:`$insertContentAtSelection` 返回「插进去没有」,插入为空时放行默认粘贴;编辑器已在更新中(回调被排队)时按原口径先接管(提交 `3391ecf7d`)。 -- 插入兜底不再留空:provider 的 `toReference` 与 `mentionToken` 都答不出来的 part 退到新增的 `contentPartText`(通用文本形态,资源落 `@resourceId`)。此前这一支会什么都不插,是「粘贴内容逐字保留」唯一的例外分支;现在没有例外。新增单测覆盖四类 part 的文本形态,新增输入区集成用例证明被破坏的 provider 契约下这段粘贴仍按文本落下,去掉兜底即变红。 -- 归一化撞名(`hero v2` 与 `hero-v2` 折成同一个 token)只在解析侧兜住、候选菜单不提示冲突,这一条涉及「哪些素材能被 @ 到」的产品取舍,未改代码,留给下一轮决定。 -- 润色回写与粘贴共用同一条落点兜底:新增 `mentionTokenOrText`(provider 的 `mentionToken`,拿不到就退 `contentPartText` 的通用文本形态),润色回写的候选扫描、整根替换的落点与粘贴插入的兜底都走它。由此润色回写不再有「provider 答不出 token 的 part 直接消失」和「整根替换时 part 解析不出引用就整条吃掉」两条静默丢弃路径;初始草稿(`applyContent`)与润色回写(`applyPolishedTextToRoot`)共用 `applyContentToRoot`,所以恢复出来的草稿里已解析不出的引用现在落成 `@resourceId` 文本而不是被吃掉。 diff --git a/docs/project-memory/plans/【实施计划】引用输入区重构与宿主注入-2026-09-22.md b/docs/project-memory/plans/【实施计划】引用输入区重构与宿主注入-2026-09-22.md deleted file mode 100644 index e2f957c43..000000000 --- a/docs/project-memory/plans/【实施计划】引用输入区重构与宿主注入-2026-09-22.md +++ /dev/null @@ -1,63 +0,0 @@ -# 引用输入区重构与宿主注入实施计划 - -对应:[引用候选由宿主注入](../../adr/【ADR】引用候选由宿主注入-2026-09-22.md);决策记录见 `docs/project-memory/shared-memory/decision-log.md` 的 2026-09-22 条目。本计划不含粘贴解析。 - -## 一句话交付与验收判据 - -把 `ResourceReferenceInput` 拆成「纯输入区 + 宿主注入的引用 provider + 独立的选择器面板」,并让附件芯片成为本轮附件的唯一事实源。 - -验收判据: - -1. 输入区不 import 任何具体引用种类,也不判断 `part.type` / `reference.type`:候选、身份解析、正文文本形态都经注入的 provider。 -2. 宿主按需选择性注入:只注入资源 → 只有 `@`;资源 + Skill → `@` 与 `$`;未注入的宿主连触发符都不存在,不需要额外的可见性开关。 -3. 素材选择器面板独立成组件、自己拿数据、由宿主渲染;输入区不再有 `versions` / `activeVersionId` / `showTriggerButton` / `onReferencePickerOpen` / `skills`。 -4. 附件导入成功后以芯片进入正文,失败或异常不插入;控制器不再持有附件数组,「待发送附件列表」删除;上限 8 按草稿中的附件芯片数计算;导入进行中禁止发送。 -5. 行为零变化:改名后芯片显示名自动刷新、打开面板前重读清单、`@`/`$` 候选与键盘交互、上限与失败提示文案逐条一致;唯一例外是已裁决的 Skill 可见性缺陷修复(非 DirectProject 宿主不再出现 `$`)。 - -## 流程判定 - -本次是无行为变化重构加两条已裁决缺陷修复(Skill 可见性、附件单一事实源),按轻量流程只建本实施计划,不新建主规范与里程碑规范;若评审要求补 SDD 里程碑,再单独补。 - -## 提交切分 - -1. **接口与 provider 工厂**:新增 `features/project-workspace/reference-source/types.ts`(`ReferenceProvider`)与四个工厂(资源 / Skill / 附件 / 运行画面区域),配规则矩阵单测:触发符有无、`match` 过滤、`toReference`、`refresh`(改名 / 删除 / 恒等)、`mentionToken`。 -2. **输入区接入注入**:输入区改为按 `providers` 派生候选菜单(不再写死两个触发符)、按数组顺序取第一个非空回答做草稿回填与改名刷新,删除 `skills` prop;测试夹具(22 处 `assets={assets}`)同批迁移为注入 provider。 -3. **面板外移**:素材选择器面板与缩略图预览搬进独立组件,宿主渲染并接线(`onConfirm → insertReferences`),输入区删除相关 props 与其死 CSS 规则(`styles.css` 里 `resource-reference-*` 共 78 条,逐条核对哪些随面板离开而失效)。 -4. **附件并入联合**:附件成为 `ChatReference` 成员,节点层收敛为单一节点类型,附件 chip 的 DOM 契约逐字保留(`data-attachment-reference`、`data-attachment-status`、`title`、移除按钮 `aria-label`)。 -5. **附件单一事实源**:`uploadFiles` 改为返回导入结果,composer 在导入成功后插入芯片、失败不插入;删除控制器附件状态、`ComposerPendingAttachments` 与提交时的附件 parts 拼接;上限改为按草稿芯片数计算,导入进行中禁止发送。 -6. **显示口径与文档**:`directCodexContentToPromptText` 的 token 前后补空白(不重复)并加 `// TODO we will rewrite this with ref as component later.`,显示名反查改由调用方注入;同步更新 `docs/【功能说明】AGC聊天素材引用-2026-09-08.md`(`ResourceReferenceInput` 共用口径、`@`/`$` 可见性、附件入口与上限口径都会变)。 - -`resource-reference-*` 的 CSS 类名重命名(78 条规则 / 15 个文件 / 22 处测试断言)留作最后一个独立机械提交,必须与 `RESOURCE_REFERENCE_OVERLAY_SELECTOR` 常量同批修改。 - -## 验证 - -每个提交后跑定向用例:`npx vitest run apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx`,加上该提交触达的宿主用例(聊天 composer / 策划输入盒 / 画布生成面板 / 资源卡快速编辑)。全部完成后跑 `npm run typecheck`、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check`,再按验收判据第 5 条逐条对照行为。真实客户端手感(候选菜单位置、面板内滚轮、附件插入位置)留待真机验收,未执行前按未验证项记录。 - -## 风险与回滚 - -- 漏注入某个宿主会让该宿主静默失去候选;fail-closed 语义正确,但必须在用例里逐宿主覆盖。 -- `LexicalTypeaheadMenuPlugin` 由两个写死实例改为按 provider 派生后,Enter 让位与 Escape 关闭口径要重新覆盖(`mentionMenuOpenRef` 需聚合成「任一菜单开着」)。 -- 附件插入位置在异步导入期间可能漂移:导入失败一律不插入;文档或选区已改动时退到草稿末尾。 -- 删除 `ComposerPendingAttachments` 会连带影响样式与既有断言,属于预期内的行为收敛,需在提交说明里写清。 -- 回滚按提交粒度 revert;无数据迁移,canonical content 形状不变。 - -## 执行状态(2026-09-22) - -已落地的提交内容: - -1. 接口与 provider 工厂:`features/project-workspace/reference-source/types.ts` + 四个工厂(资源 / Skill / 附件 / 运行画面区域),规则矩阵单测落在 `apps/ai-game-creator-shell/tests/referenceSourceProviders.test.ts`(触发符有无、`match` 过滤 / 去重 / 截断、`toReference`、`refresh`(改名 / 删除 / 恒等)、`mentionToken`、`isReady`、Skill 目录「首次 `match` 才读、失败可重试」)。 -2. 输入区接入注入:`providers` / `inputActions` / `submitSuppressed` 三个通用接缝;`skills`、`assets`、`versions`、`activeVersionId`、`showTriggerButton`、`openPicker` 全部删除;`ProviderMentionMenu` 按带触发符的 provider 派生(Enter 让位按 `mentionMenuOpenRef` 聚合)。 -3. 面板外移:`ResourceReferencePicker` + `ResourceReferencePickerAction` 由宿主渲染并接线(`onInsert → insertReferences`、`onOpenChange → submitSuppressed`),三个宿主的 `@` 触发钮位置逐处保持原样。 -4. 附件并入联合:附件成为 `ChatReference` 成员,编辑器只剩 `ResourceReferenceNode` 一种节点,附件 chip 的 DOM 契约逐字保留。 -5. 附件单一事实源:`uploadFiles(files, draftAttachmentCount)` 只返回导入成功的附件、失败不插入;控制器附件状态、`ComposerPendingAttachments`、提交时的附件 parts 拼接都删除;上限按草稿芯片数计算;导入进行中禁止发送。 -6. 显示口径与文档:`directCodexContentToPromptText(content, resolver)` 的 token 前后各补一个空白(不重复)并加 `// TODO we will rewrite this with ref as component later.`;显示名反查改由 `resourceLabelResolver(assets)` 注入;同步更新功能说明、ADR 与决策记录。 - -顺带清理:`ProjectChatComponentProps.activeVersionId` 在策划输入盒不再有 `@` 触发钮之后已无消费方,随本次删除(工作台壳自己的那份仍归 `ProjectDevelopmentView`)。 - -验证结果:`npx tsc -p tsconfig.json --noEmit`、`npm run typecheck`、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` 全通过;定向用例(`referenceSourceProviders`、`resourceReferenceInput`、`chatPromptPolish`、`resourceReferences`、画布生成面板、快速编辑、资源卡实时集成、`appSurface` 215 项、工作台壳清单合并 / 窗口同步、资源标签统计刷新、版本切换 / 替换)全绿。整仓 `npx vitest run` 仍有与本改动无关的既有环境失败(jsdom 缺 `localStorage`:`clientApi` / `clientAuthStorage` / `clientHttp` / `projectCreationDirectory` / `recentProjectsHook` 与 `src/components/image-editor/*` 若干),失败集合与本改动触及的模块不相交。 - -未完成项: - -- `resource-reference-*` CSS 类名重命名(78 条规则 / 15 个文件 / 22 处断言)仍是独立机械提交,须与 `RESOURCE_REFERENCE_OVERLAY_SELECTOR` 同批修改;本次未动,输入区与面板的既有类名逐字保留。 -- 真实客户端手感(候选菜单位置、面板内滚轮、附件插入位置、`@` 触发钮落点)未做真机验收,按未验证项记录。 -- 粘贴解析仍不在本次范围(未来接入点是 provider 的 `mentionToken` 与既有 `buildContentFromTextTokens`)。 diff --git a/docs/project-memory/plans/【实施计划】抠图模式联调验收-2026-09-16.md b/docs/project-memory/plans/【实施计划】抠图模式联调验收-2026-09-16.md index 6d6094211..a876a292d 100644 --- a/docs/project-memory/plans/【实施计划】抠图模式联调验收-2026-09-16.md +++ b/docs/project-memory/plans/【实施计划】抠图模式联调验收-2026-09-16.md @@ -1,5 +1,7 @@ # 抠图模式联调验收实施计划 +Status: implemented-awaiting-runtime-acceptance(自动化与真实上游 BgFilter 验收已执行;完整主站登录/队列/资源回写链路待本地数据库恢复) + 依据:[里程碑](./【里程碑】抠图模式联调验收-2026-09-16.md)。 1. 主站修复 worker 对 auto/省略的门禁、空值契约和旧指纹;补接口、队列与 worker 定向测试。 diff --git a/docs/project-memory/plans/【实施计划】文档素材Markdown预览-2026-09-16.md b/docs/project-memory/plans/【实施计划】文档素材Markdown预览-2026-09-16.md index 2e917adea..9b4a34837 100644 --- a/docs/project-memory/plans/【实施计划】文档素材Markdown预览-2026-09-16.md +++ b/docs/project-memory/plans/【实施计划】文档素材Markdown预览-2026-09-16.md @@ -1,7 +1,7 @@ # 文档素材 Markdown 预览实施计划 - Date: 2026-09-16 -- Status: implemented-awaiting-validation +- Status: implemented-awaiting-runtime-acceptance - Milestone: `【里程碑】文档素材Markdown预览-2026-09-16.md` ## 边界与顺序 @@ -15,3 +15,9 @@ ## 风险与回滚 重点检查高亮 class 不被自定义 code 渲染丢弃、Markdown 围栏不吞正文、弹窗 Esc 不误清画布选中、文档切换不串内容。回滚仅移除本次入口/渲染增量,保留此前工具栏修改,不改资源数据。 + +## 回归用例执行(2026-09-24) + +- `npx vitest run tests/ResourceDocumentPreviewDialog.test.tsx tests/resourceDocumentPreviewModel.test.ts tests/ChatMarkdownMessage.test.tsx`:3 文件 / **30 passed**(弹窗加载、空、失败与身份切换;预览类型与扩展名派生;Markdown 标题/列表/表格、围栏、未知语言与大正文降级)。 +- 原状态 `implemented-awaiting-validation` 的原因是「按用户此前约束不运行测试」,该约束已不适用:回归用例现在已实际执行并通过。 +- 仍未验证(需要原生客户端):真实 Tauri 命令读取文档/代码正文、弹窗焦点与滚动行为、视觉验收。 diff --git a/docs/project-memory/plans/【实施计划】游戏分发阶段A领域合同-2026-09-19.md b/docs/project-memory/plans/【实施计划】游戏分发阶段A领域合同-2026-09-19.md index 0620f55c5..def980597 100644 --- a/docs/project-memory/plans/【实施计划】游戏分发阶段A领域合同-2026-09-19.md +++ b/docs/project-memory/plans/【实施计划】游戏分发阶段A领域合同-2026-09-19.md @@ -100,7 +100,7 @@ - 真实浏览器展示验证(同一栈,headless Chromium `390x844` 与 `1280x900`):`/games` 卡片渲染真实封面签名地址(无占位回退),`/games/detail?id=…` hero 显示封面、缩略图条渲染「封面 + 2 张截图」,点击第 3 张后 `aria-pressed` 与 hero 图片同步切换;移动端布局正常。截图存于 `~/data/tmp/gd3/`(不入库)。 - 网页发布页真实上传验证(同一栈 + headless Chromium):在 `/games/publish` 里用作者会话填写资料、选择真实 PNG 封面与 ZIP 并提交,页面返回「已提交审核」;随后 `my-games` 显示该游戏 `pending_review`,版本回读的 `frozenMetadata.coverAssetId` / `coverObjectKey` 正是本次浏览器上传的素材,证明网页端封面直传(凭证 → OSS → confirm)与冻结链路真实可用。 - 发布资料入口交互打磨:原生 file 控件在上传后清空 value 时会显示「未选择任何文件」,与「已选择」提示互相矛盾;网页发布页与 AGC 面板都改成透明 input 覆盖自定义胶囊按钮(点击命中原生控件,文案显示「选择/更换封面图片」「添加截图」),并在验证中用 `elementFromPoint` 确认点击命中的是 `input[type=file]`。 -- AGC 直传能力作用域静态验证:用 `tauri-plugin-http` 同一套 `urlpattern` 解析逻辑验证 `capabilities/main.json` 新增的 `https://*.aliyuncs.com/*` 命中 dev 桶(`xushi-dev.oss-cn-beijing.aliyuncs.com/…`)与生产桶(`genarrative-assets.oss-cn-shanghai.aliyuncs.com/…`)、拒绝 `evil.example.com`;直传失败(含作用域拒绝/网络不可达)统一转成中文可操作文案,并有单测覆盖。桌面端真实执行仍需在装有 AGC 的机器上跑一次。 +- AGC 直传能力作用域静态验证:用 `tauri-plugin-http` 同一套 `urlpattern` 解析逻辑验证 `capabilities/main.json` 新增的 `https://*.aliyuncs.com/*` 命中 dev 桶(`xushi-dev.oss-cn-beijing.aliyuncs.com/…`)与生产桶(`genarrative-assets.oss-cn-shanghai.aliyuncs.com/…`)、拒绝 `evil.example.com`;直传失败(含作用域拒绝/网络不可达)统一转成中文可操作文案,并有单测覆盖。桌面端真实执行仍需在装有 AGC 的机器上跑一次。(2026-09-24 更正:AGC 素材直传已下沉 Rust `platform_asset_upload.rs`,`capabilities/main.json` 的 `https://*.aliyuncs.com/*` 作用域、`tauri-plugin-http` 插件注册与渲染层直传服务随之退役;本条历史结论只描述当时的渲染层直传实现。) - 创建游戏同步校验素材归属:此前 `POST /api/game-distribution/games` 只校验「封面必填 / 截图 ≤6 / ID 非空」,素材是否存在与是否属于当前作者要等到创建版本才失败,游戏行会先落一个无效素材 ID;现在创建游戏与创建版本都走 `resolve_owned_game_media`,不存在返回 400、他人素材返回 403。 - 合并 master(`81e0c41f1`,含 `429f991bd` 定向回滚、Godot 原生绑定迁移与策划 Agent 模型控件):回滚提交把混入 master 的游戏分发代码整体删掉,其中 25 个文件在本次合并里属于“双方都改动同一区域之外”的自动删除,直接合并会静默丢功能。处理方式是按“分支补回功能、master 保留迁移”逐类归位:模块注册(`spacetime-module/src/active.rs`)、api-server 路由与权限映射、后台审核页、AGC 发布命令与 payload 类型、`SelectionStage` 的 games 阶段、`ProjectSupervisorView` 的 `overlay` 挂载点、主站路由/标题、Cargo 依赖与锁、vite/vitest 代理与 tailwind source 全部取回分支版本;master 的 Godot C++ 迁移(删除旧 vendored GDExtension、新的 composer 控件样式)保留。合并后用“按文件对比 game-distribution 引用数不得下降”的脚本复核 85 个相关文件,无残留丢失。 diff --git a/docs/project-memory/plans/【实施计划】画布验收问题统一修复-2026-09-17.md b/docs/project-memory/plans/【实施计划】画布验收问题统一修复-2026-09-17.md index 173fe3116..b9c868300 100644 --- a/docs/project-memory/plans/【实施计划】画布验收问题统一修复-2026-09-17.md +++ b/docs/project-memory/plans/【实施计划】画布验收问题统一修复-2026-09-17.md @@ -48,3 +48,9 @@ 1. 真实客户端复验末版生成浮层可见性,以及图片/音频结果接管占位;真实 Provider 验证需先确认环境与费用。 2. 用户确认远程写入后再创建/更新 Issue、PR、推送与需求记录;本地 worktree 和提交均保留。 3. 运行时验收通过后融合持久结论并删除这两份临时计划。appSurface 异步轮询用例收尾及全量复验已经完成,证据见里程碑。 + +## 本轮复验(2026-09-24) + +- 画布与引用链路定向:`npx vitest run tests/resourceCanvasCardName.test.tsx tests/resourceCanvasBottomToolbar.test.tsx tests/resourceBookLayout.test.ts tests/resourceBookModel.test.ts tests/resourceReferenceInput.test.tsx tests/projectResourceLiveIntegration.test.tsx tests/projectResourceProjectionModel.test.ts tests/resourceCanvasAssetGenerationReferences.test.tsx --root apps/ai-game-creator-shell` → 8 文件 / **159 passed**。 +- 全量界面门禁(含工作台集成、多选移动、整理与撤销、任务占位与结算):`npm run ai-game-creator-shell:check:web` → 185 files / 1808 passed / 14 skipped;根 `npm test` → 416 files / 4391 passed / 26 skipped。 +- 仍未验证(需要真实客户端与真实 Provider):最后一版生成浮层的高度与横向居中在真实客户端复验、真实 Provider 生成 + Tauri IPC 全流程(涉及账号与费用,不默认触发)。 diff --git a/docs/project-memory/plans/【实施计划】策划Agent回合模型选择生效-2026-09-20.md b/docs/project-memory/plans/【实施计划】策划Agent回合模型选择生效-2026-09-20.md index c357c46ad..b34b791b3 100644 --- a/docs/project-memory/plans/【实施计划】策划Agent回合模型选择生效-2026-09-20.md +++ b/docs/project-memory/plans/【实施计划】策划Agent回合模型选择生效-2026-09-20.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Milestone | [回合模型选择生效里程碑](./【里程碑】策划Agent回合模型选择生效-2026-09-20.md) | -| Status | implemented(待验收) | +| Status | implemented-awaiting-runtime-acceptance | | Owner | 当前任务 Agent | ## 修改边界与顺序 @@ -43,3 +43,11 @@ | 独立静态审查 | 已检查采样入口、重放/恢复边界、请求循环和测试辅助函数可见性,无可操作发现 | 新增用例验证回合快照与旧数据读取,以及普通消息、跨工具请求、澄清回答、用户重试、审批批准、重复审批的配置生效边界。已有恢复用例继续覆盖不确定文件操作不重复执行。控件和 GameAgent 无本步修改。 + +## 延迟验证补执行(2026-09-24) + +原验证记录里「Rust 定向测试:已尝试编译,未执行测试用例」与「本地 HTTP fixture:已补充真实请求字段断言,尚未执行」两条,本轮已实际执行: + +- `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml design_runtime::tests -- --test-threads=1`:**24 passed / 0 failed**(含 `design_user_actions_apply_selection_and_tool_requests_keep_the_turn_snapshot`:本地 mock Provider 逐次捕获真实请求体,断言 `model` 与 `reasoning.effort` 跟随回合快照、运行中被改的全局配置不能改变在途回合;以及 `design_turn_selection_survives_config_changes_and_legacy_recovery`:旧记录缺 `modelSelection` 时保留会话模型、配置变化不反写已开始的回合)。 +- `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml design_session -- --test-threads=1`:**3 passed / 0 failed**。 +- 仍未运行:真实 Provider 与桌面端单回合 smoke(需要真实账号与费用)。 diff --git a/docs/project-memory/plans/【实施计划】策划Agent模型与推理档控件接入-2026-09-20.md b/docs/project-memory/plans/【实施计划】策划Agent模型与推理档控件接入-2026-09-20.md deleted file mode 100644 index 43edb6f30..000000000 --- a/docs/project-memory/plans/【实施计划】策划Agent模型与推理档控件接入-2026-09-20.md +++ /dev/null @@ -1,49 +0,0 @@ -# 策划 Agent 模型与推理档控件接入实施计划 - -| 字段 | 值 | -| --- | --- | -| Milestone | [控件接入里程碑](./【里程碑】策划Agent模型与推理档控件接入-2026-09-20.md) | -| Status | accepted | -| Owner | 当前任务 Agent | - -## 修改边界 - -- 在 `ProjectSupervisorView.tsx` 扩展既有控件排的适用范围,直接复用 `ConversationModelSelect` 与 `ComposerReasoningEffortSelect`。素材引用、语音、消息队列和停止按钮仍按原 GameAgent 条件显示。 -- 策划发送、澄清、审批和重试回调保持原样,不新增模型校验和提交门禁;GameAgent 的原校验保持不变。 -- 必要时局部调整策划宿主 CSS,避免控件换行或弹层裁切。组件内部逻辑保持不变。 -- 在现有前端测试体系补齐策划集成场景,回归已有 GameAgent 控件用例。 -- 不修改 Rust、模型生效逻辑、配置默认值、Provider 或 GameAgent 组件算法。 - -## 实现顺序 - -1. 核对共享对话容器,接入同一组控件,保留原提交路径。 -2. 补充策划控件读写、保存失败和忙态测试,回归原策划和 GameAgent 行为。 -3. 运行定向测试和类型检查,检查宽窄布局,回写证据与未验证项。 - -## 验证命令 - -- `npm test -- apps/ai-game-creator-shell/tests/appSurface.test.ts`,先按用例名称过滤控件及相关策划场景。 -- 策划宿主集成用例使用现有 Vitest / Testing Library,按实际测试文件定向运行。 -- `npm run ai-game-creator-shell:typecheck` -- `npm run check:doc-index` -- `npm run check:encoding` -- `git diff --check` - -## 风险与回滚点 - -- 防止扩大 `directCodex` 条件时带入语音、队列或改变 GameAgent 行为:仅共享控件排,保留其它分支。 -- 模型目录失败通过原选择器反馈,不给策划宿主增加前置检查,也不改造控件已有逻辑。 -- 本次回滚仅撤回前端接入、相关用例和文档,不涉及持久化数据迁移。 -- 时间盒:一个工作时段内先完成接入与定向测试,随后检查类型和布局;仅影响里程碑验收的发现纳入修复。 -- 当前已知限制:策划旧会话仍可能使用创建时模型;本次不将控件读写成功视为运行时已切换模型。 - -## 验收证据 - -| 项目 | 结果 | -| --- | --- | -| 源码边界核对 | 两个控件文件、策划动作回调、GameAgent 提交校验及 Rust 均无修改;仅扩展控件排适用条件与策划布局 | -| 定向 ESLint | `ProjectSupervisorView.tsx`、`design-agent.suite.ts`、`harness.ts` 通过 | - -定向测试命令:`npm test -- apps/ai-game-creator-shell/tests/appSurface.test.ts -t 'Design Agent|design session|clarification free text|reasoning effort control|selecting the model|model dropdown|chat composer an inset|current turn reasoning|historical reasoning'`。 - -用户已授权提交第一步、进入第二步。 diff --git a/docs/project-memory/plans/【实施计划】退役策划Agent V1V2解耦清理-2026-09-15.md b/docs/project-memory/plans/【实施计划】退役策划Agent V1V2解耦清理-2026-09-15.md index 6b6b92655..eb484638e 100644 --- a/docs/project-memory/plans/【实施计划】退役策划Agent V1V2解耦清理-2026-09-15.md +++ b/docs/project-memory/plans/【实施计划】退役策划Agent V1V2解耦清理-2026-09-15.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Milestone | `docs/project-memory/plans/【里程碑】退役策划Agent V1V2解耦清理-2026-09-15.md` | -| Status | ready | +| Status | implemented-awaiting-runtime-acceptance | | Owner | Codex | ## 一句话交付结果 @@ -90,3 +90,14 @@ ## 完成后的临时文档处理 全部里程碑验收通过后,删除本里程碑和实施计划两份临时文档;把仍然有效的长期边界同步回现行 Design Agent 技术方案和项目记忆,不保留阶段性提交步骤。 + +## 源码级验收(2026-09-24) + +- `planningSessionV2.ts` 已不存在;`src` 内检索 `planning_[a-z0-9_]*_v2` / `planningV1` / `planningV2` 无命中,做方案入口只调用 `design_agent_session` / `continue_design_agent_session` / `hydrate_design_agent_session` 等当前 Design Agent IPC。 +- 旧 Plan GDD 类型与旧策划流工厂已清空:本轮删掉测试 harness 里无调用方、且引用了已不存在类型的 `createPlanGddStateView` 与 `planningResponseStream`(两者原本还导出给 suite);`PlanGdd` / `planning-session-v2-stream` 在 `src` 与 `tests` 已无命中。 +- 旧策划样式无残留:`plan-gdd` / `planning-lane` / `gdd-approval` 在 `src` 样式与组件内无命中。 +- Rust 侧同批退役见 decision-log 2026-09-21 条目:`planning_gdd_model.rs`、`planning_policy_v2.rs`、`planning_session_v2.rs`、`planning_*_v2` 命令与前端契约全部删除,不保留兼容别名或双跑路径。 +- 自动化:`npx vitest run tests/appSurface.test.ts tests/gamePublishFeedback.test.tsx` 195 passed / 9 skipped;`npm run ai-game-creator-shell:check:web` 185 files passed / 1 skipped、1806 tests passed;`npm run check:doc-index`、`npm run check:encoding`、`git diff --check` 通过。 +- 仍未取得:真实“做方案”新项目进入 Design Agent、已有会话恢复、澄清与阶段审批回合在真机 + 真实 Provider 下的连续验收。 + +因此状态从 `proposed` / `ready` 改为 `implemented-awaiting-runtime-acceptance`:源码级判据全部成立,缺真机运行时证据。 diff --git a/docs/project-memory/plans/【实施计划】退役策划V2 Rust Runtime清理-2026-09-14.md b/docs/project-memory/plans/【实施计划】退役策划V2 Rust Runtime清理-2026-09-14.md deleted file mode 100644 index ebe9f1d74..000000000 --- a/docs/project-memory/plans/【实施计划】退役策划V2 Rust Runtime清理-2026-09-14.md +++ /dev/null @@ -1,21 +0,0 @@ -# 关联里程碑 - -`【里程碑】退役策划V2 Rust Runtime清理-2026-09-14.md` - -# 修改顺序 - -1. 从 `runtime_protocol.rs` 移除 V2 模块声明与导出。 -2. 从 `main.rs` / `commands.rs` 移除 V2 command 注册和仅供 V2 的导入。 -3. 删除 V2 Rust 模块及其专属单元测试;保留共享 GDD 模型或新版设计会话仍使用的类型。 -4. 用 `rg` 检查 V2 Rust 符号残留,修复编译引用。 - -# 验证命令 - -- `cargo check --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml` -- `npm run check:encoding` -- `git diff --check` - -# 风险与回滚 - -- 风险:V2 类型可能被共享测试或前端桥接代码引用。处理方式是按编译错误逐项判断,保留真正共享类型。 -- 回滚:按提交粒度回退本里程碑提交,不触碰前序 V1 清理提交。 diff --git a/docs/project-memory/plans/【实施计划】项目客户端占用锁收敛-2026-09-14.md b/docs/project-memory/plans/【实施计划】项目客户端占用锁收敛-2026-09-14.md index e579a6514..0c535ca4f 100644 --- a/docs/project-memory/plans/【实施计划】项目客户端占用锁收敛-2026-09-14.md +++ b/docs/project-memory/plans/【实施计划】项目客户端占用锁收敛-2026-09-14.md @@ -35,3 +35,30 @@ Milestone: `【里程碑】项目客户端占用锁收敛-2026-09-14.md` - 旧 `.agent/runtime/execution-owner.lock` 残留需要按 PID/启动身份安全回收,不能直接删除。 - 复用判据按线程判定:出现同进程跨线程重入的现场时先按 `*_locked` 入口处置,不要把判据退回按 `pid` 一律放行(那会放过并行写,见里程碑「边界」末条)。 - 若跨 boot 恢复或 GUI/Runner 联动回归,回滚统一路径迁移,保留已验证的同进程重入修复。 + +## 锁现状盘点与卡点(2026-09-24) + +验收标准 1/2/3/5 本轮已实测成立,第 4 条(客户端占用入口与 Runtime 写入入口不各自维护第二个项目级锁文件)卡在一个必须由产品/架构决定的问题上,不能在实现里单方面选。 + +### 现存的项目级锁文件(全量枚举) + +- `.agent/project.lock`(`src/main.rs` 的 `PROJECT_WRITE_LOCK_PATH`,`project/write_lock.rs`):GUI 侧每个写命令的短时写锁;同线程重入复用、其它线程/进程有界等待与终态占用、死进程残留回收都在这一把上。 +- `.agent/runtime/execution-owner.lock`(`runner/protocol.rs` 的 `EXTERNAL_AGENT_RUNNER_PROJECT_OWNER_PATH`):Runner 进程的跨进程 execution owner,配 `.agent/runtime/execution-owner.json` 诊断投影。 +- `.agent/workbench/resource-layouts/.layout.lock`、项目历史的 `append.lock`:子资源与追加写的底层一致性机制,不属于本里程碑说的「项目级占用」。 + +### 为什么第 4 条不能直接落地 + +- Runner 的 owner 是**长时锁**:`runner/state.rs` 的 `project_execution_owners` 在首次 `claim_project_execution_owner` 后保留到进程结束(claim 只在 dispatch 的写请求入口发生,没有释放路径),而 `.agent/project.lock` 是**逐操作短时锁**,GUI 侧 30+ 个写命令(`commands.rs` 里成片的 `acquire_project_write_lock`)都依赖它。 +- 因此「Runner 长时持有 `.agent/project.lock`」等于在 Runner 存活期间让所有 GUI 写命令变成「项目正在被其他写操作占用」——这是语义回退,不是收敛。两条可行路线都会改变现有产品行为,必须选一条: + - 路线 A(Runner 成为项目唯一写者):GUI 的写命令改为经 Runner 转发。CLI 侧已经是这个口径(`require_external_agent_runner_for_cli_runtime_write`),但 GUI 侧改动面很大,需要单独立项与灰度。 + - 路线 B(改执行占用的判据):用占用记录 + 持有者 liveness 取代 OS 锁。这与 shared-memory 决策记录 2026-07-12 的安全合同直接冲突——「execution-owner 的 OS 锁文件与 JSON 诊断投影分离……诊断内容不得作为接管依据」,接管必须依靠稳定目录句柄上的系统锁,不能降级成读 JSON 判 owner。 +- 结论:第 4 条不是实现细节,是要先定「谁写项目」或「是否修改执行占用的安全合同」。在决定之前,本里程碑保持 `in-progress`,执行占用的恢复诊断合同不变(主规范 2026-09-14 小节已写明「完成前不改变其恢复诊断合同」)。 + +### 本轮实测(验收标准 1/2/3/5) + +- 同一线程重入复用、释放后可再次取得:`project_write_lock_reuses_same_process_owner_and_releases_on_drop`。 +- 本进程其它线程持锁时仍走有界等待:`steer_consumption_waits_across_a_legitimate_longer_project_write`、`provider_plan_waits_across_an_autonomous_manifest_wave_project_write`、`runtime_parallel_read_projection_waits_across_a_manifest_wave_project_write`。 +- 跨进程占用与残留回收:`project_write_lock_contention_names_a_live_external_holder`、`project_write_lock_reclaims_dead_owner_pid`、`project_write_lock_reclaims_pid_reused_by_other_live_process`、`project_write_lock_reclaims_empty_body_after_short_grace`、`project_write_lock_keeps_matching_process_identity`。 +- 命令:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 project_write_lock` 全绿(含 `project::write_lock` 与 `tests::project_lock_recovery` 分组)。 +- Runner owner 的跨 AppData / 跨 boot / 恢复与诊断覆盖已经存在,并且本轮实跑通过:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 project_execution_owner` → **8 passed**(含 `project_execution_owner_is_unique_across_appdata_and_records_recovery`、`project_execution_owner_cross_boot_claim_recovers_durable_runtime_once`、`project_execution_owner_concurrent_claims_single_flight_recovery`、`tests::response_stream::project_execution_owner_cross_boot_replays_same_run_provider_handoff_to_completion_once`);`… --test-threads=1 owner_diagnostic` → **4 passed**(含 `corrupt_legacy_owner_diagnostic_does_not_block_lock_recovery`、`partial_owner_diagnostic_is_atomically_recovered_after_os_lock`)。 +- 平台边界:`project_owner_relative_open_does_not_follow_parent_replacement_race` 与 `project_execution_owner_rejects_symlinked_runtime_parent_without_touching_target` 都是 `#[cfg(unix)]`,本机(Windows)不执行,本次没有它们的证据。 diff --git a/docs/project-memory/plans/【实施计划】项目自动上传与后台工程下载-2026-09-19.md b/docs/project-memory/plans/【实施计划】项目自动上传与后台工程下载-2026-09-19.md index 3fb6c6e41..16d15cc1a 100644 --- a/docs/project-memory/plans/【实施计划】项目自动上传与后台工程下载-2026-09-19.md +++ b/docs/project-memory/plans/【实施计划】项目自动上传与后台工程下载-2026-09-19.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Milestone | `docs/project-memory/plans/【里程碑】项目自动上传与后台工程下载-2026-09-19.md` | -| Status | implemented-awaiting-runtime-validation | +| Status | implemented-awaiting-runtime-acceptance | | Owner | 当前任务 Agent | ## 修改边界 @@ -30,3 +30,10 @@ ## 风险与回滚 旧清单无完整性声明,只能标记未知;完整工程含项目源码、素材和配置,排除依赖/构建缓存、凭据、会话与运行日志。下载失败不修改 OSS 或清单。本轮按用户授权提交推送,不部署;代码可独立回退。 + +## 本轮复验(2026-09-24) + +- 服务端与共享契约:`cargo test --locked -p platform-oss` → **74 passed**;`cargo test --locked -p shared-contracts` → **96 + 2 + 2 passed**;`cargo test --locked -p api-server project_snapshot -- --test-threads=1` → **21 passed / 1 ignored**。 +- 客户端:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml project_snapshot -- --test-threads=1` → **24 passed / 1 ignored**(ignored 是真实 OSS live smoke)。 +- 后台:`npm run admin-web:typecheck` 通过;`npm run admin-web:build` 成功(1820 modules,产物 579 kB / gzip 164 kB);`npx vitest run apps/admin-web/src/pages/AdminAgcTemplatesPage.test.tsx apps/admin-web/src/api/adminApiClient.test.ts` → 36 passed(列表/编辑/上传入口)。 +- 仍未验证(需要本地数据库与新客户端):`npm run dev:api-server` 就绪后的后台列表/ZIP HTTP 联调、新客户端安装版下的隔离实机自动上传。 diff --git a/docs/project-memory/plans/【里程碑】AGC macOS渠道更新落地-2026-09-17.md b/docs/project-memory/plans/【里程碑】AGC macOS渠道更新落地-2026-09-17.md index fd0a4fc32..6a7391ff9 100644 --- a/docs/project-memory/plans/【里程碑】AGC macOS渠道更新落地-2026-09-17.md +++ b/docs/project-memory/plans/【里程碑】AGC macOS渠道更新落地-2026-09-17.md @@ -3,7 +3,7 @@ | 字段 | 值 | | ----------- | ------------------------------------------------------------------ | | Version | 1.0 | -| Status | in-progress | +| Status | implemented-awaiting-runtime-acceptance(需要 macOS 构建节点与真机升级验收) | | Date | 2026-09-17 | | Parent Spec | `docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md` | @@ -46,3 +46,11 @@ - 自动化:macOS 更新产物选择与清单生成用例、仓库门禁。 - 运行时:macOS 上一次真实更新闭环(含重启后版本核对),OSS 对象与清单核对。 - 边界:签名校验失败、公证缺失、渠道缺少 macOS 平台条目、跨架构不匹配时的表现。 + +## 本轮复核(2026-09-24) + +- 客户端侧重启收敛已落地:`src-tauri/src/main.rs` 的 `restart_agc_app`(`app.restart()` + 重启埋点)已在 `generate_handler!` 注册(`main.rs:2824`),供 macOS 安装完成后由客户端接管新版本。 +- 构建与准备脚本齐备:`apps/ai-game-creator-shell/scripts/build-macos-ci.mjs`、`prepare-macos-codex.mjs`、`check-macos-bundle.mjs`;对应用例在 `node --test build-release.test.mjs release-oss.test.mjs prepare-macos-codex.test.mjs cargo-features.test.mjs` 的 **60 passed** 批次内(含 `macOS manifests advertise exactly the architectures actually built`、渠道 DMG 首装选择、渠道分区隔离)。 +- 仍未验证(需要 macOS 节点):真实 macOS 构建与 DMG 产出、Apple 签名与公证、安装后重启接管新版本、`dev-mac` 渠道真实发布。 + +因此状态从 `in-progress` 改为 `implemented-awaiting-runtime-acceptance`:代码与脚本判据成立,缺的是 macOS 环境证据。 diff --git a/docs/project-memory/plans/【里程碑】AGC发行包分片续传上传-2026-09-23.md b/docs/project-memory/plans/【里程碑】AGC发行包分片续传上传-2026-09-23.md index a881e7e88..dd057c435 100644 --- a/docs/project-memory/plans/【里程碑】AGC发行包分片续传上传-2026-09-23.md +++ b/docs/project-memory/plans/【里程碑】AGC发行包分片续传上传-2026-09-23.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Version | 1.0 | -| Status | runtime-smoke-passed(真实栈「中断 → 续传 → 确认」已通过;AGC 真机一键发布与 200 MiB 档容量数据未验证) | +| Status | implemented-awaiting-runtime-acceptance(真实栈「中断 → 续传 → 确认」已通过;AGC 真机一键发布与 200 MiB 档容量数据未验证) | | Date | 2026-09-23 | | Parent Spec | `docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`(真实发行包与资料合同第 10 条、幂等并发与恢复) | diff --git a/docs/project-memory/plans/【里程碑】AGC客户端更新切换到官方更新插件-2026-09-17.md b/docs/project-memory/plans/【里程碑】AGC客户端更新切换到官方更新插件-2026-09-17.md index 48930772e..025cae983 100644 --- a/docs/project-memory/plans/【里程碑】AGC客户端更新切换到官方更新插件-2026-09-17.md +++ b/docs/project-memory/plans/【里程碑】AGC客户端更新切换到官方更新插件-2026-09-17.md @@ -3,7 +3,7 @@ | 字段 | 值 | | ----------- | ------------------------------------------------------------------ | | Version | 1.0 | -| Status | approved | +| Status | implemented-awaiting-runtime-acceptance | | Date | 2026-09-17 | | Parent Spec | `docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md` | @@ -33,13 +33,29 @@ ## 验收标准 - [ ] 正式包走官方更新插件的检查与安装路径;更新包校验失败时必须拒绝安装并清理临时文件。 -- [ ] 客户端只请求本渠道清单,且不因清单缺失、格式错误或网络失败阻塞启动。 -- [ ] 开发态启动不产生任何更新清单请求,也不显示更新入口。 -- [ ] 更新能力只授予客户端主窗口,其它窗口调用被拒绝。 -- [ ] 自研清单解析、下载命令、下载进度事件与相应的 CSP / HTTP 白名单放行整条删除,无残留兼容分支。 +- [x] 客户端只请求本渠道清单,且不因清单缺失、格式错误或网络失败阻塞启动。 +- [x] 开发态启动不产生任何更新清单请求,也不显示更新入口。 +- [x] 更新能力只授予客户端主窗口,其它窗口调用被拒绝。 +- [x] 自研清单解析、下载命令、下载进度事件与相应的 CSP / HTTP 白名单放行整条删除,无残留兼容分支。 ## 证据要求 - 自动化:前端定向用例(渠道映射、开发态开关、失败关闭)、原生侧定向用例、类型检查与仓库门禁。 - 运行时:`agc` 开发启动无清单请求;使用测试渠道清单完成一次真实检查与安装闭环(含升级后重启)。 - 边界:签名不匹配、下载中断、清单 404、渠道缺少当前平台条目、非主窗口调用。 + +## 本轮复核(2026-09-24) + +状态原为 `approved` / `ready`(规范评审态),实现其实已经落地,本轮按当前工作树复核并改记为 `implemented-awaiting-runtime-acceptance`: + +- 原生侧接入官方插件:`apps/ai-game-creator-shell/src-tauri/Cargo.toml` 有 `tauri-plugin-updater = "2.11.0"`;`tauri.conf.json` 打开 `createUpdaterArtifacts` 并写入 `plugins.updater.pubkey` 与渠道端点。 +- 自研更新链路已删除:`download_ai_game_creator_update` / `install_ai_game_creator_update` / `check_ai_game_creator_update` 在 `src-tauri/src` 与 `src` 内均无命中;前端更新服务 `src/services/appUpdate.ts` 只消费官方插件包,而该包是 IPC 薄壳,网络与安装都在 Rust 侧。 +- 未执行(需要签名私钥与发布授权):真实签名打包、真实 OSS 发布、安装后真机升级与回滚。 + +## 逐条勾选依据(2026-09-24) + +- 条目 2:渠道端点在构建期写入(`channel manifest URL and build-time endpoint follow the channel` 用例),客户端只读本渠道 `latest.json`;`AppUpdateNotice` 在 effect 里异步 `checkForAppUpdate()`,服务失败静默返回结果,不阻塞启动。 +- 条目 3:`resolveAppUpdateCheckEnabled(flag, dev) = resolveFeatureFlag(flag, { devValue: false, dev })`,`WindowChrome` 只在 `appUpdateCheckEnabled` 为真时渲染 ``,开发态既不请求也不显示入口。 +- 条目 4:`src-tauri/capabilities/main.json` 的 `"windows": ["client"]` 且承载 updater 权限,其它窗口没有该能力。 +- 条目 5:`rg "download_ai_game_creator_update|install_ai_game_creator_update|check_ai_game_creator_update"` 在 `src` 与 `src-tauri/src` 内 0 命中;退役 OSS 白名单未恢复(原生 HTTP scope 已对齐官方 updater 权限)。 +- 未勾选的条目 1:正式包走官方插件路径已由依赖与配置证明,但「校验失败必须拒绝安装并清理临时文件」是插件内部行为,需要真实发布包与篡改样本才能验收。 diff --git a/docs/project-memory/plans/【里程碑】AGC工作区偏好IO下沉Rust-2026-09-23.md b/docs/project-memory/plans/【里程碑】AGC工作区偏好IO下沉Rust-2026-09-23.md new file mode 100644 index 000000000..73dfaa12e --- /dev/null +++ b/docs/project-memory/plans/【里程碑】AGC工作区偏好IO下沉Rust-2026-09-23.md @@ -0,0 +1,58 @@ +# 【里程碑】AGC 工作区偏好 IO 下沉 Rust + +Version: `v1` +Status: `implemented-awaiting-runtime-acceptance` +Date: `2026-09-23` +Parent Spec: `docs/technical/【技术方案】AGC后端框架整理与演进路线-2026-09-18.md` + +## 目标 + +把 AGC 启动器的正式工作区偏好交给 Tauri Rust 持有:项目创建目录和最近工作区写入 AppData 下的受控 JSON,由 typed command 读取/写入并通过事件通知 React。React 只保留当前页面投影、输入草稿和按钮交互,不再直接访问 `localStorage`,建项命令也不再从 React 传递已持有的偏好值。 + +## 范围 + +- Rust AppData 偏好文件的 schema、版本、原子写入、损坏回退和最近工作区路径校验。 +- `read/write/reset_project_creation_directory` 与 `read/add/remove_recent_workspace` typed commands。 +- 项目创建目录与最近工作区变更事件;事件 payload 只含受控偏好投影,不含凭据。 +- React `features/app-shell/model.ts`、`useProjectCreationDirectory.ts`、`useRecentProjects.ts` 改为 Tauri command/event façade。 +- 首页自动建项与模板建项从 Rust 读取偏好,React 不再把 `projectsRoot` 作为正式数据传入。 + +## 非目标 + +- 不迁移 access token、服务器选择、钱包、账户 HTTP 或发送前提醒偏好。 +- 不迁移 Home 输入草稿;它是用户尚未提交的短暂输入状态,继续由 React 内存保存。 +- 不改变项目 manifest、SpacetimeDB schema、公开 HTTP API 或现有 Rust 建项安全门禁。 + +## 行为合同 + +1. 首次读取先返回空最近列表和空创建目录;不存在或无法解析的偏好文件不得阻断启动。 +2. 最近工作区最多保留 8 个规范化绝对路径,新增置顶、重复去重;移除不存在的路径也必须幂等。 +3. 项目创建目录仅作为用户意图保存;真正建项仍由 Rust 每次执行目录安全校验,空值回退默认 AppData projects 目录。 +4. Rust 写入偏好后先完成落盘,再发送对应事件;事件丢失时 React 允许一次受控快照读取,不恢复固定定时器。 +5. 事件和 command 返回不包含 access token、API key、cookie 或未经授权的本地文件内容;绝对路径仅限用户明确选择或已登记的工作区路径。 +6. 多窗口/重复命令按内容签名去重事件;事件订阅卸载和迟到事件不得写回已失效页面。 + +## 验收证据 + +- Rust 偏好模块单测覆盖首次空态、非法 JSON、路径校验、8 条上限、置顶去重、移除幂等和原子写入。 +- React 定向测试覆盖 command façade、事件更新、浏览器预览回退、建项调用不再携带 `projectsRoot`。 +- `npm --prefix apps/ai-game-creator-shell run typecheck`、AGC Web 门禁、相关 Rust `cargo test`、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check`。 + +## 迁移与回滚 + +- 首次启动可读取旧 localStorage 键并由一次显式迁移 command 写入 Rust 偏好;迁移成功后清理旧键,失败保留旧值但不阻断页面。 +- 若事件桥不可用,React 仅在挂载时读取一次快照;Rust 偏好仍是唯一持久化真相。 +- 回滚只回退 React façade 和迁移入口,不删除 Rust 偏好文件或改变现有建项门禁。 + +## 实施状态 + +- Rust AppData `workspace-preferences.json`、typed commands 与变更事件已落地。 +- 项目创建目录与最近工作区的 React 读取/写入已切换到 invoke/event façade;Home 输入草稿、账户凭据、钱包和发送前提醒未纳入本批。 +- 定向 Rust/React 测试、TypeScript 检查和完整 command allowlist 已通过;完整 Web 门禁待本轮最终复验。 + +## 本轮取证(2026-09-24) + +- 行为合同 1/2/3(偏好文件缺失不阻断启动、最近工作区最多 8 条去重幂等、创建目录只表达意图且建项仍过 Rust 门禁):`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- workspace_preferences --test-threads=1` → **6 passed**。 +- 范围项(React 不再直接访问 `localStorage`、建项不再由 React 传 `projectsRoot`):`rg localStorage apps/ai-game-creator-shell/src` 只剩 `features/app-shell/workspacePreferences.ts` 的旧键迁移 shim(`isTestRuntime()` 门控);`rg projectsRoot apps/ai-game-creator-shell/src` **0 命中**。 +- 前端 façade:`npx vitest run tests/recentProjectsHook.test.tsx tests/projectCreationDirectory.test.ts --root apps/ai-game-creator-shell` → **5 + 4 passed**(命令/事件投影、失败重试与偏好读写)。 +- 仍未验证(需要真实客户端):多窗口并发改偏好、事件丢一次后的受控快照读取、真实建项落到用户所选目录。 diff --git a/docs/project-memory/plans/【里程碑】AGC工作区网络IO下沉Rust-2026-09-23.md b/docs/project-memory/plans/【里程碑】AGC工作区网络IO下沉Rust-2026-09-23.md new file mode 100644 index 000000000..9d518f0b0 --- /dev/null +++ b/docs/project-memory/plans/【里程碑】AGC工作区网络IO下沉Rust-2026-09-23.md @@ -0,0 +1,44 @@ +# 【里程碑】AGC 工作区网络 I/O 下沉 Rust + +Version: `v1` +Status: `implemented-awaiting-runtime-acceptance` +Date: `2026-09-23` +Parent Spec: `docs/technical/【技术方案】AGC后端框架整理与演进路线-2026-09-18.md` + +## 目标 + +让 AGC 项目工作区的网络请求由 Tauri Rust typed facade 统一编排。React 只提交领域命令、展示 Rust 返回的投影和消费事件,不持有 access token、不拼接任意 URL、不轮询远端任务。 + +## 范围 + +- 发行资料、封面生成、发行游戏/版本/送审和发行包上传。 +- 工作区素材库/模型目录/资源读取与素材上传中至少一个完整闭环,优先复用现有 Rust `assets` / `resource_editor` / `http_client` 能力。 +- Rust 侧负责 origin、认证会话、幂等键、重试分类、远端异步任务事件和失败关闭。 + +## 非目标 + +- 本里程碑不迁移登录、刷新 cookie、短信、钱包充值等账户生命周期;这些需要独立的 Auth/PlatformSession 合同。 +- 不新增任意 URL + 任意 method 的通用 HTTP IPC 代理。 +- 不改变公开 HTTP API、SpacetimeDB schema、OpenAPI 或项目 manifest。 + +## 验收标准 + +1. 发行与选定工作区资源闭环的 React 源码不再 import `requestClientApi` / `fetchClientHttp` / access token storage。 +2. Rust typed command 只接受结构化业务参数,服务端地址与认证由 Rust 当前会话/配置决定;事件 payload 不含 token、API key、cookie 或任意本地绝对路径。 +3. 远端异步状态由 Rust 事件或 bounded channel 通知,静止时无 React `setInterval` 轮询。 +4. 同一 idempotency key、401/403、429/5xx、unknown result 和取消路径都有定向测试;未知结果不自动重放付费副作用。 +5. React 只渲染命令结果/事件投影,页面卸载不会丢失 Rust 在途操作或产生重复请求。 +6. `npm run ai-game-creator-shell:check:web`、相关 Rust 测试、编码、文档索引和 diff 检查通过。 + +## 未决边界 + +- 账户登录与钱包仍保留现有独立链路,直到 Auth/PlatformSession 里程碑冻结 token 归属和跨窗口语义。 +- 真实 Provider、远端支付和生产发行 smoke 仍需单独环境证据,静态/fixture 测试不能替代。 + +## 本轮取证(2026-09-24) + +- 验收 1(React 不再直连):`rg "requestClientApi|fetchClientHttp|accessToken|refreshToken" apps/ai-game-creator-shell/src` → **0 命中**;`rg projectsRoot apps/ai-game-creator-shell/src` → 0 命中。 +- 验收 3(静止时无 React 轮询):`rg setInterval apps/ai-game-creator-shell/src` 只剩两类非远端任务——计时/动画(`AuthenticatedClient` 的登录耗时与验证码倒计时、`useLiveNow`、`useDesignReplyAnimation`、`DirectProjectConversation` 的本地时钟)和拖拽重复器(`TransformEditor`)。 +- 验收 4/5 的定向用例:`npx vitest run tests/gameDistributionPublish.test.ts tests/assetDirectUpload.test.ts tests/pluginHost.test.ts tests/directActiveTurns.test.tsx tests/resourceCanvasAssetGenerationQueue.test.ts tests/recentProjectsHook.test.tsx tests/projectCreationDirectory.test.ts --root apps/ai-game-creator-shell` → **7 文件 / 63 passed**。 +- 补直接单测(2026-09-24):`clientHttp.ts` 收敛成「服务器选择 + base URL 解析」后原先只有 `appSurface/auth.suite.ts` 的happy path(回环 http 可选中并落盘)。新增 `apps/ai-game-creator-shell/tests/clientHttp.test.ts` **5 passed**:拒绝无效 URL、非 HTTP(S)、带凭据、带路径/查询/哈希的地址与非回环明文 http(逐条断言错误原因),合法地址去尾斜杠并保留回环端口,预设到渠道地址的映射,开发态切换落盘 + 内存生效,`hydrateClientServerSelection` 从 Rust 偏好恢复。变异验证:拿掉带凭据的拒绝条件后「带凭据地址」那条变红。 +- 仍未验证(需要真实环境):真实 OSS 发行包上传与送审、真实账户下的发行资料生成、发布取消/未知结果的端到端表现;「打包态不开放服务器切换」因 `import.meta.env.DEV` 在测试运行下恒为 true,只能在真实发布构建里核对(已写在用例注释里)。 diff --git a/docs/project-memory/plans/【里程碑】AGC总版本号落地-2026-09-20.md b/docs/project-memory/plans/【里程碑】AGC总版本号落地-2026-09-20.md index a8913f5ff..b43b8901c 100644 --- a/docs/project-memory/plans/【里程碑】AGC总版本号落地-2026-09-20.md +++ b/docs/project-memory/plans/【里程碑】AGC总版本号落地-2026-09-20.md @@ -1,6 +1,6 @@ # 里程碑:AGC 总版本号落地 -状态:进行中(主规范已定稿,代码与 CI 已实现,等待首次真实统一构建验收) +状态:implemented-awaiting-runtime-acceptance(主规范已定稿、代码与 CI 已实现,等待首次真实统一构建验收) ## 关联文档 @@ -35,3 +35,9 @@ - 首次真实播种与统一构建尚未执行(避免在功能未合并前烧号)。 - `feat/jenkins-mac-build` 分支上的 macOS 管线仍用旧的自增高水位逻辑;该分支合并 master 后才继承本方案的模块与断言,合并前 dev-mac 必须由发号 Job 显式传入 `AGC_RELEASE_VERSION`。 + +## 本轮复验(2026-09-24) + +- 发号与清单脚本:`node --test apps/ai-game-creator-shell/scripts/agc-global-version.test.mjs` → **8 passed**(低于渠道清单的号失败关闭、写后回读不一致失败关闭、`nextVersion` 只在 patch 位递增、ossutil 默认 v1 签名并可切 region/v4)。 +- 发布管线脚本(含渠道清单与签名失败关闭):`node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs apps/ai-game-creator-shell/scripts/release-oss.test.mjs apps/ai-game-creator-shell/scripts/prepare-macos-codex.test.mjs apps/ai-game-creator-shell/scripts/cargo-features.test.mjs` → **60 passed**。 +- 仍未验证(需要 CI 与发布环境):首次真实统一构建(Jenkins 全链路)与真实渠道发号写入。 diff --git a/docs/project-memory/plans/【里程碑】AGC更新发布管线渠道化-2026-09-17.md b/docs/project-memory/plans/【里程碑】AGC更新发布管线渠道化-2026-09-17.md index 3498047bd..575ae0615 100644 --- a/docs/project-memory/plans/【里程碑】AGC更新发布管线渠道化-2026-09-17.md +++ b/docs/project-memory/plans/【里程碑】AGC更新发布管线渠道化-2026-09-17.md @@ -3,7 +3,7 @@ | 字段 | 值 | | ----------- | ------------------------------------------------------------------ | | Version | 1.0 | -| Status | approved | +| Status | implemented-awaiting-runtime-acceptance | | Date | 2026-09-17 | | Parent Spec | `docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md` | @@ -13,7 +13,7 @@ ## 范围 -- 构建期按渠道生成清单:版本按渠道独立递增,清单包含该渠道平台的下载地址与签名;macOS 自 2026-09-21 起只出 arm64 单架构,`dev-mac` 只登记 `darwin-aarch64`(原 universal 双键口径已作废:随包 Node 只有单架构官方发行版,需先实现双架构运行时才能恢复 Intel,见 `docs/project-memory/shared-memory/decision-log.md`)。 +- 构建期按渠道生成清单:版本来自统一总号(OSS `agc/global-version.json`,渠道高水位降级为断言;见 `docs/technical/【技术方案】AGC总版本号与发号-2026-09-20.md`),清单包含该渠道平台的下载地址与签名;macOS 自 2026-09-21 起只出 arm64 单架构,`dev-mac` 只登记 `darwin-aarch64`(原 universal 双键口径已作废:随包 Node 只有单架构官方发行版,需先实现双架构运行时才能恢复 Intel,见 `docs/project-memory/shared-memory/decision-log.md`)。 - 构建期生成更新产物签名,并在缺少签名私钥或私钥不可用时失败关闭。 - 渠道参数与目标平台绑定校验:Windows 目标只能发布 `dev-win`,macOS 目标只能发布 `dev-mac`;未显式指定时按目标平台取默认渠道。 - 上传按渠道落位:安装包与签名进版本目录,清单覆盖写渠道路径的 latest 指针。 @@ -33,15 +33,32 @@ ## 验收标准 -- [ ] 指定渠道发布时该渠道清单版本按渠道独立递增,另一个渠道清单不受影响。 -- [ ] 渠道与目标平台不匹配、缺少签名私钥或私钥密码错误时发布失败关闭,不产生半成品清单。 +- [x] 渠道清单版本来自统一总号;显式传入的号低于本渠道当前清单版本时构建失败关闭,另一个渠道清单不受影响(原「按渠道独立递增」口径已由 2026-09-20 总版本号方案取代)。 +- [x] 渠道与目标平台不匹配、缺少签名私钥或私钥密码错误时发布失败关闭,不产生半成品清单。 - [ ] 发布后 OSS 上安装包、签名与渠道清单三者一致:清单内地址指向已存在的对象,签名与安装包匹配。 -- [ ] universal macOS 产物的两个平台键指向同一对象同一签名,不存在只挂单一架构键或指向不存在对象的情况。 +- [x] universal macOS 产物的两个平台键指向同一对象同一签名,不存在只挂单一架构键或指向不存在对象的情况。 - [ ] Jenkins 归档与日志中不出现签名私钥内容,凭据只注入构建进程。 -- [ ] 未显式指定渠道时按目标平台取默认渠道,且 `--no-bundle` smoke 路径仍不读远端版本、不改版本、不生成清单。 +- [x] 未显式指定渠道时按目标平台取默认渠道,且 `--no-bundle` smoke 路径仍不读远端版本、不改版本、不生成清单。 ## 证据要求 - 自动化:发布脚本单测(渠道解析与校验、版本递增、清单结构、签名缺失失败关闭)、仓库门禁。 - 运行时:一次真实渠道发布加 OSS 对象核对(清单、安装包、签名),并用该清单触发一次客户端更新闭环。 - 边界:渠道与平台不匹配、签名密钥缺失、远端清单 404、远端清单格式非法、重复发布时的 latest 覆盖。 + +## 本轮复核(2026-09-24) + +状态原为 `approved` / `ready`(规范评审态),实现其实已经落地,本轮按当前工作树复核并改记为 `implemented-awaiting-runtime-acceptance`: + +- 渠道单点定义 `apps/ai-game-creator-shell/scripts/channel-identity.mjs`;`build-release.mjs` 由它解析渠道,渠道清单 URL 与构建期端点随渠道变化。 +- 流水线渠道参数:`jenkins/Jenkinsfile.ai-game-creator-shell-build` 有 `AGC_UPDATE_CHANNEL`(dev / release / 自定义小写名)并把部署目标绑定为渠道对应的构建分区。 +- 定向测试(本轮实跑):`node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs apps/ai-game-creator-shell/scripts/release-oss.test.mjs apps/ai-game-creator-shell/scripts/prepare-macos-codex.test.mjs apps/ai-game-creator-shell/scripts/cargo-features.test.mjs` → **60 passed / 0 failed**,含 `channel manifest carries version, platform keys and signature`、`missing signature fails the channel manifest closed`、`channel manifest URL and build-time endpoint follow the channel`、`release windows uploads only its own partition and cannot write the dev bridge`。 +- 未执行(需要签名私钥与发布授权):真实签名打包、真实 OSS 上传、各渠道真机升级验证。 + +## 逐条勾选依据(2026-09-24) + +- 条目 2:`node --test build-release.test.mjs release-oss.test.mjs prepare-macos-codex.test.mjs cargo-features.test.mjs`(本轮实跑 60 passed)内的 `invalid target or platform used as channel fails before any release side effect`、`missing signature fails the channel manifest closed`。 +- 条目 4:同一批的 `universal uses the Mac channel and the same signed artifact for both architectures`(构造真实签名产物后断言两个平台键指向同一对象同一签名)。 +- 条目 6:同一批的 `no-bundle smoke skips version writes and manifest generation`、`release context resolves explicit targets before environment/default and fails closed`。 +- 条目 1:原验收口径「按渠道独立递增」已被 2026-09-20 的总版本号方案取代——`build-release.mjs` 的 `prepareReleaseVersion()` 用统一总号,`resolveRemoteHighWaterVersion(channel, target)` 只做本渠道高水位断言(`assertRequestedVersionNotBelowChannel`);`node --test scripts/agc-global-version.test.mjs` → 8 passed,含「传入低于本渠道清单的号时失败关闭」「写后回读不一致失败关闭」「nextVersion 只在 patch 位递增」。本文件的范围与条目已按当前口径改写。 +- 仍未勾选:条目 3(发布后 OSS 三者一致需要真实发布);条目 5(Jenkins 日志/归档不含私钥需要真实流水线证据)。 diff --git a/docs/project-memory/plans/【里程碑】AGC模板库客户端接入-2026-09-17.md b/docs/project-memory/plans/【里程碑】AGC模板库客户端接入-2026-09-17.md deleted file mode 100644 index 6272c2d1b..000000000 --- a/docs/project-memory/plans/【里程碑】AGC模板库客户端接入-2026-09-17.md +++ /dev/null @@ -1,54 +0,0 @@ -# AGC 模板库客户端接入 - -Version: 1.0 -Status: accepted(2026-09-21 复核:7 条验收项均有定向、前端与线上真连证据) -Date: 2026-09-17 -Parent Spec: `docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md` - -## 目标 - -AGC 客户端能读取公共 OSS 上的游戏模板库,并把「浏览 → 筛选 → 下载 → 用模板建项目」做成一条可用链路,模板更新不再依赖客户端发版。 - -## 范围 - -- OSS `templates/` 前缀的库布局、清单 schema、封面与 zip 元数据契约。 -- Rust 侧读取清单、下载安装、由模板创建项目的命令与安全边界。 -- 模板库全屏页(搜索、标签/运行时筛选、仅看已下载)、首页模板推荐位、左侧导航入口。 -- 仓库内发布脚本与文档、模板库定向单测与类型检查。 - -## 不做 - -- 不做模板制作工具、模板审核、模板计费与推荐算法。 -- 不做模板增量更新(按 `templateVersion` 全量重下)。 -- 不把模板回填进已创建项目,也不改写用户项目内容。 -- 不放宽现有项目私有 DACL、下载摘要校验和受信任 OSS 主机边界。 - -## 验收标准 - -1. `fetch_game_template_library` 能读到清单并合并本机已安装状态;远端不可用时回退本机缓存并标明 `source=cache`。 -2. `download_game_template` 对字节数与 SHA-256 不一致、越界对象键、非 `templates/` 前缀的包一律拒绝,且不落半成品目录。 -3. zip 解压拒绝绝对路径、`..`、盘符、符号链接;安装完成后才写 `installed.json` 作为已下载判据。 -4. `create_automatic_local_game_project_from_template` 建出的项目同时具备模板文件、`.agent` 清单与标准目录;失败时不留项目目录。 -5. 模板库页可按关键词、标签、运行时与「仅看已下载」筛选;卡片显示封面与已下载徽标;已下载且版本一致时不再显示下载入口(落后显示「更新」);过程提示以浮层 toast 呈现,不占页面内位置;「使用模板」在版本落后时先重下再建项。 -6. 首页推荐位展示模板库内容并可进入模板库页;左侧导航有模板库入口且为独立全屏页。 -7. 定向 Rust 单测 9 项(含线上清单 fixture)、前端模型 9 项 + 页面/推荐位 8 项、`tsc` 类型检查、`npm run check:encoding`、`git diff --check` 全部通过;可选真连检查能读线上清单、下载安装线上模板并据此建项目。 - -## 依赖 - -- 现有自动工作区建项链路(`create_automatic_local_game_project_at` / `init_local_game_project_at`)。 -- 现有 AGC 更新通道使用的受信任 OSS 主机与 CSP 白名单口径。 -- 仓库 OSS 凭据(本机 `.env.secrets.local` 的 `ALIYUN_OSS_*`)与 `scripts/agc-template-library-publish.mjs`。 - -## 验收证据(2026-09-21) - -| 验收项 | 证据 | -| --- | --- | -| 1 读清单 + 合并已安装状态 + 远端不可用回退缓存并标 `source=cache` | `template_library::tests::template_index_*` 5 项(网络优先并标 `network`、远端失败回退缓存并标 `cache`、无缓存暴露远端错误、远端正文非法不用缓存掩盖、缓存损坏失败关闭);`fetches_the_live_template_library_index` 真连通过 | -| 2 下载拒绝字节数 / SHA-256 / 越界键 / 非 `templates/` 前缀,且不落半成品 | `rejects_archive_when_size_or_digest_do_not_match_the_index`(含新增断言:拒绝后无安装目录、无已下载判据)、`rejects_object_keys_outside_the_templates_prefix`、`rejects_template_base_url_outside_trusted_oss`;`downloads_and_installs_a_live_template` 真连通过 | -| 3 解压拒绝绝对路径 / `..` / 盘符 / 符号链接;安装完成才写 `installed.json` | `rejects_archive_entries_that_escape_the_destination`(含新增断言:失败后不产生安装记录)、`installs_template_archive_and_reports_it_as_installed`、`parses_content_addressed_objects_without_changing_the_template_contract` | -| 4 建项具备模板文件 + `.agent` + 标准目录,失败不留项目目录 | `creates_project_from_installed_template_without_leaking_install_marker`、`installs_official_cocos_templates_and_creates_native_projects`、新增 `failed_project_creation_removes_the_partial_project_directory`、`refuses_to_create_project_when_template_is_not_installed`;`downloads_and_creates_live_cocos_templates` 真连通过 | -| 5 页面筛选 / 卡片 / 已下载徽标 / 更新入口 / 浮层提示 / 版本落后先重下 | `templateLibraryView.test.tsx` 12 项、`templateLibraryModel.test.ts` 9 项、`templateLibraryGrid.test.ts` 6 项、`useTemplateLibrary.test.tsx` 11 项 | -| 6 首页推荐位与左侧导航入口 | `appSurface.test.ts` 首页模板用例 2 项:灰度外隐藏入口与推荐位、点击推荐位进入模板库且不建项目 | -| 7 定向用例 + 类型 / 编码 / 文档检查 + 可选真连 | Rust 24 项 + 线上 3 项、前端 38 项 + `appSurface` 2 项、AGC `typecheck`、`check:encoding`、`check:doc-index`、`git diff --check` 全部通过;匿名 `GET templates/index.json` 返回 200(`schemaVersion=agc-template-library.v1`、9 个模板) | - -仍未验证:Creator 内场景运行;真机 iOS / Android 观感。持久结论已并入主规范 [`【技术方案】AGC模板库与模板建项-2026-09-17.md`](../../technical/【技术方案】AGC模板库与模板建项-2026-09-17.md),本里程碑的实施计划已按工作流删除。 diff --git a/docs/project-memory/plans/【里程碑】AGC渠道安装身份隔离-2026-09-21.md b/docs/project-memory/plans/【里程碑】AGC渠道安装身份隔离-2026-09-21.md index dea7272cd..167dadebb 100644 --- a/docs/project-memory/plans/【里程碑】AGC渠道安装身份隔离-2026-09-21.md +++ b/docs/project-memory/plans/【里程碑】AGC渠道安装身份隔离-2026-09-21.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Version | 1.0 | -| Status | 代码与源码级验收已落地,等待真机双渠道安装验收 | +| Status | implemented-awaiting-runtime-acceptance(代码与源码级验收已落地,等待真机双渠道安装验收) | | Date | 2026-09-21 | | Parent Spec | `docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md` | @@ -42,3 +42,8 @@ - 自动化:`build-release.test.mjs`、`release-oss.test.mjs`、`prepare-macos-codex.test.mjs`、`check-config.mjs` 与 Rust `config::tests::` 定向测试。 - 运行时:单渠道 `--no-bundle` 构建烟测;真机双渠道安装、并存与各自更新。 - 边界:非法渠道失败关闭;默认渠道身份不变;相似前缀目录不进入 managed 赋权范围。 + +## 本轮复验(2026-09-24) + +- `node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs apps/ai-game-creator-shell/scripts/release-oss.test.mjs apps/ai-game-creator-shell/scripts/prepare-macos-codex.test.mjs apps/ai-game-creator-shell/scripts/cargo-features.test.mjs`:**60 passed / 0 failed**,含「release / beta 的 Windows 与 macOS 构建只写自己渠道分区、不能写 dev 桥」四条分区隔离用例。 +- 仍未执行:真实渠道打包(需要签名私钥与发号/上传授权)、双渠道真机并存安装、macOS 构建节点实跑。 diff --git a/docs/project-memory/plans/【里程碑】AGC渲染层事件化与Rust数据源-2026-09-23.md b/docs/project-memory/plans/【里程碑】AGC渲染层事件化与Rust数据源-2026-09-23.md new file mode 100644 index 000000000..ea886cdd0 --- /dev/null +++ b/docs/project-memory/plans/【里程碑】AGC渲染层事件化与Rust数据源-2026-09-23.md @@ -0,0 +1,48 @@ +# 【里程碑】AGC 渲染层事件化与 Rust 数据源 + +Version: `v1` +Status: `implemented-awaiting-runtime-acceptance` +Date: `2026-09-23` +Parent Spec: `docs/technical/【技术方案】AGC后端框架整理与演进路线-2026-09-18.md` + +## 目标 + +在 AGC 项目工作区与本地 Runtime 链路中,明确 Rust/Tauri 是正式数据与 I/O 的持有方,React 只保留展示、用户输入和短暂 UI 状态。状态变化由 Rust 事件通知,首次进入或事件可能丢失时只做一次受控快照读取,不建立固定频率轮询。 + +## 范围 + +- Direct 活动回合列表:由 Rust 活动注册表变更事件驱动。 +- 本地素材生成任务:由 Rust 账本变更事件驱动,保留一次恢复快照读取。 +- Runtime 设置中的 AGC 插件状态:由 Rust 插件状态事件驱动,保留显式刷新。 +- 保留两处已修复的无限 `setState` 回归测试,并补充事件订阅/去重/卸载测试。 +- Direct Thread Manager 订阅释放以及策划对话写入失败的自触发重试修复。 + +## 非目标 + +- 本里程碑不改公开 HTTP API、SpacetimeDB schema、项目 manifest 或 Agent Runtime 持久化格式。 +- 登录、账户钱包、外部发行 API 的 React 直连网络迁移另列后续里程碑;本轮先不把账户生命周期与工作区事件改造混在一起。 +- 纯 UI 计时器、拖拽长按重复器和动画 tick 不作为业务轮询处理。 + +## 验收标准 + +1. AGC 工作区代码中 Direct 活动回合与本地素材生成任务不再设置固定 `setInterval` 轮询。 +2. Rust 在活动回合登记、更新、结束和素材生成账本状态变化时发出快照/更新事件;事件 payload 不含凭据或未脱敏项目内容。 +3. React 订阅先于首次快照读取,事件重复或内容未变时不产生新的数组状态引用;卸载后迟到事件不能写回。 +4. 插件状态页进入时读取一次,状态变更事件即时更新,用户操作仍可显式刷新;不再每秒读取。 +5. 现有无限 `setState` 回归测试继续通过,并新增事件驱动竞态测试。 +6. 定向 Web/Rust 测试、`npm run check:encoding`、`git diff --check` 通过。 +7. Direct 组件卸载(包括 bootstrap 晚到)后 Rust subscriber 被幂等注销,不再发送无消费者通知;移除慢订阅后可清理已消费事件。 +8. 策划对话落盘失败后不因 effect 自增版本继续重试;权限查询合并,用户可从明确动作重新触发,不能把未知写入结果当成未写入而自动重放。 + +## 风险与回滚 + +- 事件订阅可能在注册回执前错过一次通知,因此所有入口先订阅再做一次快照读取;快照失败保留上一份状态并给出读取失败标记。 +- 事件只能减少读取,不能替代持久化账本;重开项目仍从 Rust 账本恢复。 +- 若某个事件桥在浏览器预览或测试环境不可用,使用一次性快照读取,不恢复定时轮询。 + +## 本轮取证(2026-09-24) + +- 验收 1(活动回合与素材任务不再定时轮询):`rg setInterval` 全仓只剩计时/动画与拖拽重复器;`directActiveTurns.ts` 走 `DIRECT_ACTIVE_TURNS_CHANGED_EVENT` 事件 + 单飞读取并在注释里写明「不恢复定时轮询」,`resourceCanvasAssetGenerationQueue.ts` 走 `game-creator-asset-generation-task-changed` 事件(Rust 在账本状态变更处 emit),事件桥不可用时才回退注入的 wait。 +- 验收 3/7(订阅先于快照、重复事件不换数组身份、卸载后迟到事件不写回、subscriber 幂等注销):`npx vitest run tests/directActiveTurns.test.tsx tests/resourceCanvasAssetGenerationQueue.test.ts --root apps/ai-game-creator-shell` → **11 + 19 passed**;Rust 侧 `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- direct_thread_manager --test-threads=1` → **13 passed**。 +- 验收 4(插件状态:进入读一次 + 事件更新 + 显式刷新):`npx vitest run tests/pluginHost.test.ts --root apps/ai-game-creator-shell` → **14 passed**。 +- 仍未验证(需要真实客户端):长回合中插件状态事件与素材任务事件的真实时序、真实 Provider 生成下的任务账本事件密度。 diff --git a/docs/project-memory/plans/【里程碑】AGC画布交互稳定性修复-2026-09-16.md b/docs/project-memory/plans/【里程碑】AGC画布交互稳定性修复-2026-09-16.md index de82fa9ef..805e2e669 100644 --- a/docs/project-memory/plans/【里程碑】AGC画布交互稳定性修复-2026-09-16.md +++ b/docs/project-memory/plans/【里程碑】AGC画布交互稳定性修复-2026-09-16.md @@ -1,7 +1,7 @@ # AGC 画布交互稳定性修复 - Version: 1 -- Status: reviewed +- Status: implemented-awaiting-runtime-acceptance - Date: 2026-09-16 - Parent Spec: [AGC 实施计划:资源画布交互与工作台状态同步](../../technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md) diff --git a/docs/project-memory/plans/【里程碑】AGC统一错误诊断与验收反馈-2026-09-15.md b/docs/project-memory/plans/【里程碑】AGC统一错误诊断与验收反馈-2026-09-15.md index bcc95ef90..622d6aa9f 100644 --- a/docs/project-memory/plans/【里程碑】AGC统一错误诊断与验收反馈-2026-09-15.md +++ b/docs/project-memory/plans/【里程碑】AGC统一错误诊断与验收反馈-2026-09-15.md @@ -1,7 +1,7 @@ # AGC 统一错误诊断与验收反馈 Version: 1.0 -Status: active +Status: implemented-awaiting-runtime-acceptance Date: 2026-09-15 Parent Spec: `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的“2026-09-15 AGC 统一错误事件、诊断落库与验收反馈” @@ -37,3 +37,19 @@ Parent Spec: `docs/technical/【技术方案】AI游戏创作智能体App实施 - 现有 `direct_project_history`、`runtime_state`、`codex_app_server`、`direct_tool_bridge` 与浏览器 validation 证据。 - 现有 DirectProject 诊断 sidecar 和 manifest 资源身份。 + +## 当前进度(2026-09-24) + +- 已落地并验证:统一错误事件模型与脱敏(`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 runtime_error` → 7 passed)、DirectProject 失败安全投影与项目内 sidecar、下一轮诊断上下文、app-server 终态与超时分类、试玩 attempt 上限。 +- 本轮补缺口:渲染层取回 `detailRef` 的口径抽成 `apps/ai-game-creator-shell/src/services/agentRuntimeErrorDetail.ts`,新增 `tests/agentRuntimeErrorDetail.test.ts`(4 条);Rust 侧新增 `direct_codex_failure_text_keeps_the_detail_ref_marker_for_the_renderer` 钉住同一份文案。两侧用例互相引用用例名,改文案或改解析都会变红(文案标记过去只在渲染层内联正则里,两侧都没有测试)。 +- 仍未完成的是验收标准 6 的交互项:诊断正文目前随失败文案一次性读回并展示,尚未做成「点击详情后才读取」的展开入口。要继续的话先在主规范里定交互,再改 UI;在那之前本里程碑保持 `active`,不按已完成收口。 + +## 报告缺口关闭(2026-09-24) + +上一轮记录里「验收标准 6 的交互项未完成」已经实现,本轮把计划从 `active` 改记为 `implemented-awaiting-runtime-acceptance`: + +- 修掉一个真实缺陷:Native 已经下发 `direct-codex-failure:v2`(在 v1 之上多了 `code=` 与末尾 `;详情:`),但渲染层映射只认 v1,任何 DirectProject 失败都被兜底成「执行失败,请稍后重试」,Rust 精心产出的阶段、摘要与建议全部被丢掉。现在 v1 / v2 共用同一套脱敏与阶段映射(v2 用例在 `tests/agentRuntimeModel.test.ts`,移除 v2 分支该用例变红;2026-09-24 复核:把正则里的 `:v2` 改成 `:v3` 后该文件精确 1 条失败、其余 18 条通过,声明已被独立复现)。 +- 失败提示不再预读也不内联诊断正文:控制器只把安全 `publicText` 交给面板,`detailRef` 与提示文案分开持有;聊天状态栏下方新增「查看详情 / 收起详情」入口,展开时才调用 `read_agent_runtime_error_detail`(原生命令仍做目录校验与二次脱敏),读不到只显示一句说明,不影响提示本身。 +- 钉住这条交互的用例:`tests/appSurface/chat-composer.suite.ts` 的「失败提示保留可执行原因,诊断正文只在「查看详情」时读取」(断言点击前没有 `read_agent_runtime_error_detail` 调用、正文不在提示或历史消息里,点击后按 `projectPath + detailRef` 读取并展示,再点收起)。 +- 自动化:`npx vitest run tests/agentRuntimeModel.test.ts tests/agentRuntimeErrorDetail.test.ts`(23 passed)、`npx vitest run tests/appSurface.test.ts`(191 passed / 9 skipped)、`npx tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit`、`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 runtime_error`(7 passed)。 +- 仍未验证(需要真实账号与 Provider):真实失败回合下从提示进入详情、以及下一轮追问从历史读取失败证据的端到端表现。 diff --git a/docs/project-memory/plans/【里程碑】AGC认证会话与账户网络下沉Rust-2026-09-24.md b/docs/project-memory/plans/【里程碑】AGC认证会话与账户网络下沉Rust-2026-09-24.md new file mode 100644 index 000000000..2a42939c1 --- /dev/null +++ b/docs/project-memory/plans/【里程碑】AGC认证会话与账户网络下沉Rust-2026-09-24.md @@ -0,0 +1,107 @@ +# 【里程碑】AGC 认证会话与账户网络下沉 Rust + +Version: `v1` +Status: `implemented-awaiting-runtime-acceptance` +Date: `2026-09-24` +Parent Spec: `docs/technical/【技术方案】AGC后端框架整理与演进路线-2026-09-18.md` + +## 目标 + +把 AGC 剩余的前端直连网络与凭据持有收口到 Tauri Rust:登录、验证码、refresh、登出、 +服务器选择、账户钱包与充值兑换全部由 Rust typed command 执行,Rust 是 access token 与 +refresh 凭据的唯一持有方;React 只渲染 Rust 投影、表达用户意图并在事件到达时更新。 + +## 范围 + +- Rust 认证会话存储:AppData 私有 JSON 持有 `apiBaseUrl`、`userId` 与 refresh cookie + (名称 + 值),原子写入、损坏回退、换号/origin 变化失败关闭。 +- Rust typed commands:`read_client_auth_state`、`send_client_phone_login_code`、 + `login_client_with_password`、`login_client_with_phone_code`、`logout_client_session`、 + `refresh_client_auth_session`、`read/set_client_server_selection`。 +- Rust 账户命令:profile dashboard、充值中心、创建充值订单、确认微信充值、钱包账单、兑换码。 +- Rust 自身在登录、续期、登出时安装/清除本地运行时会话(含 Runner 传播),并发出会话事件。 +- 渲染层删除 access token 的持久化与读取、`fetchClientHttp` 直连、`clientApi` 账户与 + 钱包请求;`AuthenticatedClient`、`platformSession`、`useAccountWallet`、`useWalletStore` + 改为消费 Rust command/事件。 + +## 非目标 + +- 不改变 `api-server` 的认证路由、cookie 名称、cookie 属性、refresh 轮换语义或 + SpacetimeDB schema。 +- 不把 access token、refresh cookie 值放进事件 payload、错误文案、日志或诊断包。 +- 不新增任意 URL + 任意 method 的通用 HTTP IPC 代理;服务器选择只允许 release / dev / + 本机或 HTTPS 自定义 origin。 +- 不改主站(网站)认证链路。 + +## 行为合同 + +1. Rust 是会话事实源:access token 只存在于 Rust 内存与本地运行时会话安装结果中;渲染层 + 任何模块都不得读取、缓存或持久化 token 或 refresh cookie。 +2. 登录成功后 Rust 必须完成「持久化 refresh 凭据 → 安装本地运行时会话 → 发出会话事件」, + 再向调用方返回用户投影;任一步失败按失败关闭,不能只更新一半状态。 +3. access token 过期(401)时由 Rust 用本地 refresh 凭据续期并重放原请求一次;续期被 + 服务端明确否认(401/403)才判定会话失效并清除本地凭据,网络/5xx 保留会话。 +4. 换号、登出或 origin 变化必须让旧身份在途请求失败关闭;同一身份 token 轮换不得使在途 + 请求失效。 +5. 并发续期在同一进程内合并为一次;跨进程(多窗口)读到已被轮换的旧凭据时允许重新读取 + 本地凭据后重试一次,仍失败才判定失效。 +6. 服务器选择只在本地 Vite debug 可用;打包产物始终跟随构建渠道。origin 校验与 + `normalizeClientServerBaseUrl` 同口径(纯 HTTP(S)、无凭据、非本机必须 HTTPS)。 +7. 事件只承载状态投影(`status`、`user`、`apiBaseUrl`、`error` 分类),不含 token、 + cookie、refresh 值或任意本地路径。 +8. 钱包、充值、兑换命令只提交结构化业务参数;订单创建与确认保持与现有网站同一条 + `POST /api/profile/recharge/orders`、`POST .../wechat/confirm` 合同,未知结果不自动重放。 +9. 浏览器预览(无 Tauri host)时认证能力明确不可用,不回退到渲染层直连网络。 + +## 验收标准 + +1. `apps/ai-game-creator-shell/src` 内不再出现 access token / refresh cookie 的读取、写入或 + 持久化;`fetchClientHttp` 与 `clientApi` 的账户、钱包、认证调用点被删除。 +2. Rust 单元测试覆盖:凭据文件原子写入与损坏回退、origin 校验、并发续期合并、401 续期 + 重放一次、续期被拒后清除、换号/登出失败关闭、事件不含敏感字段。 +3. React 定向测试覆盖:登录/验证码/登出命令调用、会话事件更新、钱包与充值命令调用、 + 订单失败不重放、无 native host 时明确失败。 +4. `npm run ai-game-creator-shell:check:web`、相关 Rust 定向测试、`npm run check:encoding`、 + `npm run check:doc-index`、`git diff --check` 通过。 +5. 明确报告未验证项:真实账号登录/续期/微信支付、多窗口并发刷新与真实发行端点仍需环境证据。 + +## 迁移与回滚 + +- 一次性迁移:若渲染层仍存在旧 access token localStorage 键,Rust 首次读取会话时忽略它, + 由用户在需要时重新登录;不把旧 token 当作 refresh 凭据迁移。 +- 回滚点是 React façade 与 command 注册;Rust 凭据文件删除即回到未登录状态,不改变服务端 + 会话与既有数据。 +- 迁移期间保留旧 `install/clear_platform_account_session` command,便于按账号策略回退; + 冻结验收后删除渲染层调用方,command 是否保留按现役调用方决定。 + +## 实施状态 + +- Rust `auth_session` 持有凭据文件、origin 校验、登录/验证码/续期/登出 HTTP 与本机运行时会话安装;渲染层只提交结构化参数并消费状态投影与事件。 +- 渲染层已无 access token / refresh cookie 的读写,也无 `fetch` 调用:`clientApi` 删除,`clientHttp` 收敛为 origin 校验与渠道默认值,服务器选择迁到 Rust 客户端偏好。 +- Direct 回合保活同样归 Rust:回合登记时启动保活任务、回合结束即停止,渲染层不再有业务定时器。\n- 自动化证据见 `【实施计划】AGC认证会话与账户网络下沉Rust-2026-09-24.md` 的「当前验证记录」;真实账号、多窗口并发刷新与付费路径仍需运行时验收。 +## 验收标准覆盖情况(逐条) + +| 标准 | 证据 | 结论 | +| --- | --- | --- | +| 1. `src` 内不再有凭据读写,`fetchClientHttp` / `clientApi` 调用点删除 | `rg 'fetch\(|requestClientApi|getStoredAuthAccessToken' src` 无命中;`services/clientApi.ts` 已删除、`clientHttp.ts` 收敛为 origin 校验 | 达成 | +| 2a. 凭据文件原子写入与损坏回退 | `auth_session::tests::session_files_must_be_complete_and_round_trip_atomically`、`corrupt_or_foreign_session_files_never_authenticate`(坏 JSON、字段缺失、空值 cookie 全部按未登录处理) | 达成 | +| 2b. origin 校验 | `origins_reject_credentials_paths_and_plain_remote_http`、`channel_origins_are_always_accepted_and_normalized` | 达成 | +| 2c. 并发续期合并 | `concurrent_refresh_reuses_a_session_rotated_while_waiting`(等锁期间已被轮换则复用,不再轮换第二次)+ 单飞锁 | 达成 | +| 2d. 401 续期重放一次 | Rust 只返回稳定分类,重放由渲染层 façade 承担:`accountHost` 的「登录失效时续期一次并重放」「续期期间换号时不重放旧身份付费请求」 | 达成(边界在渲染层,非 Rust 内部) | +| 2e. 续期被拒后清除 | 分类(`session_routes_classify_401_403_as_authority_failures`)与清除写入(`session_files...` 的 clear 断言)都有单测;"401 → 清文件"的端到端组合需要真实登录服务,仍属运行时验收项 | 部分:组件级已覆盖 | +| 2f. 换号/登出失败关闭 | `credential_rotated_elsewhere`(不同 user/origin 不复用)、`reserve_session_write` 身份代次语义、`platform_session` 既有的跨身份拒绝 | 达成 | +| 2g. 事件不含敏感字段 | `auth_state_events_never_carry_credentials`(序列化里不含 token/cookie/refresh 等标记) | 达成 | +| 3. React 定向测试 | `clientAuthHost` 6/6、appSurface 认证切片 12/12、`accountHost` 3/3、`walletStore` 14/14 | 达成 | +| 4. 门禁通过 | 见实施计划「当前验证记录」 | 达成 | +| 5. 明确报告未验证项 | 实施计划末条 + 本节 2e | 达成 | + +## 本轮取证(2026-09-24) + +- 原生定向(同一批过滤一次跑完 42 项):`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- workspace_preferences account_api platform_asset_upload auth_session error_report::submit direct_thread_manager --test-threads=1` → **42 passed**。 +- 分组明细:`auth_session::` **12 passed**(会话存储所有权与权限、origin 校验、6 条命令的错误分类)、`account_api::` **4 passed**、`platform_asset_upload::` **3 passed**、`workspace_preferences` 6、`direct_thread_manager` 13、`error_report::submit` 含在其中。 +- 结构:`rg "accessToken|refreshToken" apps/ai-game-creator-shell/src` → 0 命中(渲染层不再持有凭据);`localStorage` 只剩偏好迁移 shim。 +- 补代次语义直接单测(2026-09-24):新增 `apps/ai-game-creator-shell/tests/platformSession.test.ts` **7 passed**,把 `platformSession.ts` 注释里那几条不变量变成可执行断言——同一身份重复采纳(StrictMode 双次 hydrate)不推进代次、换 origin 与换账号各推进一次、代次订阅只在真变化时触发、期望代次过期时不采纳身份、登录切换/登出立刻推进、同一账号续期不推进代次且并发续期只发一次请求、续期发现未登录时采纳空身份并标记权威失败、续期期间换号返回 `stale`、网络类失败保持会话且不标记权威失败。变异验证:拿掉「同一身份提前返回」后,StrictMode 那条用例变红。 +- 补直接单测(2026-09-24):新增 `apps/ai-game-creator-shell/tests/platformSessionRetry.test.ts` **7 passed**,把 2d/2f 的边界从「facade 层 + mock 掉 `platformSession`」下沉为直接单测——错误分类的 4 真 4 假样本;请求期间换号/登出不续期也不重放;续期失败抛回原始错误;续期成功只重放一次;以及「续期完成瞬间换号」必须抛 `登录账号已变化,原请求已停止`。变异验证:分别拿掉「请求后代次围栏」与「refresh.generation 比对」,对应两条用例各变红一次。 +- Rust 侧变异验证之二(2026-09-24):把 `ClientSessionFile::is_complete()` 直接改成 `true`(即不再校验 api_base_url / user_id / refresh cookie 名值四段)后,`corrupt_or_foreign_session_files_never_authenticate` 精确挂在「空值 refresh cookie(登出清理形态)」那条 `read_session_file_at(&path).is_none()` 上,说明「半份/清空凭据不得进入续期链路」这条不变量确实被守住;改回后 `corrupt_or_foreign_session_files` exit 0。 +- Rust 侧变异验证(2026-09-24):拿掉 `auth_session::validate_client_api_base_url` 里「地址不得包含凭据」的拒绝后,`origins_reject_credentials_paths_and_plain_remote_http` 精确在 `https://user:pass@example.com` 那条断言处变红(`assertion failed: ... .is_err()`),说明这条安全用例不是空跑;改回后 `auth_session::tests` 12 条恢复全绿,`cargo fmt -- --check` 通过。 +- 仍未验证(需要真实账号):真实登录/续期/登出、微信支付、多窗口并发刷新、真实 Provider 回合跨 token 过期。 diff --git a/docs/project-memory/plans/【里程碑】AGC资源JSON语义识别-2026-09-16.md b/docs/project-memory/plans/【里程碑】AGC资源JSON语义识别-2026-09-16.md index 119c04f27..f19dbc679 100644 --- a/docs/project-memory/plans/【里程碑】AGC资源JSON语义识别-2026-09-16.md +++ b/docs/project-memory/plans/【里程碑】AGC资源JSON语义识别-2026-09-16.md @@ -1,7 +1,7 @@ # AGC 资源 JSON 语义识别 - Version: 1 -- Status: reviewed +- Status: implemented-awaiting-runtime-acceptance - Date: 2026-09-16 - Parent Spec: [AGC 实施计划:文档与代码素材预览](../../technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md) diff --git a/docs/project-memory/plans/【里程碑】AGC资源kind枚举化Rust绑定与内部收紧-2026-09-15.md b/docs/project-memory/plans/【里程碑】AGC资源kind枚举化Rust绑定与内部收紧-2026-09-15.md deleted file mode 100644 index 221d37578..000000000 --- a/docs/project-memory/plans/【里程碑】AGC资源kind枚举化Rust绑定与内部收紧-2026-09-15.md +++ /dev/null @@ -1,40 +0,0 @@ -# 【里程碑】AGC 资源 kind 枚举化 Rust 绑定与内部收紧 - -| 字段 | 值 | -| --- | --- | -| Version | 1.0 | -| Status | complete | -| Date | 2026-09-15 | -| Parent Spec | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` | - -## 目标 - -将 GameCreationApp 资源 kind 从 shell 内裸字符串收紧为 Rust `GameCreationAppAssetKind`,并生成 shell 专属 TypeScript 绑定;所有同语义内部字段使用该类型,未知输入解析为 `Unknown` 并记录日志。 - -## 范围 - -- Rust enum、serde kebab-case、`Unknown` 与 category 派生边界。 -- ts-rs feature-gated 生成入口、生成文件和 verify 门禁。 -- `packages/shared/src/contracts/gameCreationApp.ts` 中重复的资源 kind 手写契约迁入 shell 生成绑定后的删除/收口。 -- shell 内资源 kind 参数、投影、筛选、Agent 资源引用和 manifest 读写边界的类型收紧。 - -## 不在范围内 - -- server-side 其他 `asset_kind`、External API DTO、SpacetimeDB schema;仅纳入 api-server 图片快速编辑对 GameCreationApp manifest 来源的严格校验。 -- `source.kind`、`generationKind`、MIME 和文件格式。 -- 其他领域字段为配合本里程碑进行“顺手枚举化”。 - -## 依赖与前置条件 - -- 词汇审计里程碑通过并关闭所有阻塞项。 -- 生成目录、TS 导入路径、Unknown 日志字段和 writer 禁止主动写 Unknown 的规则已确认。 - -## 验收标准 - -- [x] Rust enum 与生成的 TS 绑定值逐项一致,JSON 使用 kebab-case;正式资源成员为当前 17 个 canonical kind 加 `font`,另有 `Unknown` 解析成员。TS 侧不再手写值集合,改为对生成 union 做穷举 `Record`。 -- [x] 未知输入得到 `Unknown`,日志包含原始值与调用上下文(`parse_with_context` + 壳层在 `main()` 注册的 `app_log!` 回调,见 2026-09-17 收敛)。 -- [x] 生产 writer 不再接受裸 `string` 作为 GameCreationApp kind(manifest 写入、资源登记、direct runtime、平台美术登记、资源编辑派生均只传枚举成员);`Unknown` 仅表示解析边界无法判定,调用方可拒绝或交后续归类。 -- [x] `font`、`audio`、`sound-effect`、`background-music` 均有真实生产路径(字体导入、上传音频推断、资源编辑音频派生)。 -- [x] ts-rs 绑定由 `cargo test export_bindings` 生成,生成目录加入 `.prettierignore` / eslint `ignorePatterns`,可幂等复现且不污染工作树。 -- [x] 退役的 `BindingDTO` / `BindingChange` 不再导出,手写的 `exports_ui_editor_types` 已删除。 -- [x] 旧 alias 不再由共享契约把非 canonical 输入收口成 canonical;api-server 图片快速编辑不再保留 legacy 兼容白名单,非 canonical 来源直接失败。 diff --git a/docs/project-memory/plans/【里程碑】AGC资源kind枚举化写入方清理与验证-2026-09-15.md b/docs/project-memory/plans/【里程碑】AGC资源kind枚举化写入方清理与验证-2026-09-15.md deleted file mode 100644 index d1b1626e7..000000000 --- a/docs/project-memory/plans/【里程碑】AGC资源kind枚举化写入方清理与验证-2026-09-15.md +++ /dev/null @@ -1,37 +0,0 @@ -# 【里程碑】AGC 资源 kind 枚举化写入方清理与验证 - -| 字段 | 值 | -| --- | --- | -| Version | 1.0 | -| Status | complete | -| Date | 2026-09-15 | -| Parent Spec | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` | - -## 目标 - -逐处修正 shell 内仍产生非正式 GameCreationApp kind 的生产代码;保留仅属于 workflow、generation、路径或其他领域的字符串,并为这些边界补充清晰类型/命名说明而不扩大本 PR。 - -## 范围 - -- manifest 登记、恢复、回填、资源替换、画板/图集导出、字体导入、上传推断和 Agent 资源登记。 -- shell 前端资源投影、筛选和资源引用消费方。 -- 删除 alias/fallback 生产逻辑及其只服务于旧值的测试。 -- 对仍保留的 workflow、generation、路径和其他领域字符串完成边界核对,不将其重新解释为 manifest kind。 - -## 不在范围内 - -- 不改 `source.kind`、`generationKind` 等其他字段,即使它们恰好使用同名值。 -- 不修改 server-side 代码或公开 API。 -- 不实现字体格式/MIME enum;`font` 只作为本次 manifest asset kind 成员。 - -## 依赖与前置条件 - -- Rust/TS 绑定里程碑通过。 -- 写入方扫描清单中每个 alias 都已有“manifest kind / 其他领域 / 删除”结论。 - -## 验收标准 - -- [x] 新建、导入、生成、恢复、替换路径不会写入未纳入 enum 的 manifest kind。 -- [x] 未知外部值只进入 `Unknown` 并有 trace;缺失输入的中性默认仅由明确登记入口决定。 -- [x] `source.kind` 与 `generationKind` 的既有字符串行为不变。 -- [x] 定向 Rust、TS、绑定生成、编码和 diff 检查通过。 diff --git a/docs/project-memory/plans/【里程碑】AGC资源kind枚举化词汇审计与绑定架构-2026-09-15.md b/docs/project-memory/plans/【里程碑】AGC资源kind枚举化词汇审计与绑定架构-2026-09-15.md deleted file mode 100644 index 782798962..000000000 --- a/docs/project-memory/plans/【里程碑】AGC资源kind枚举化词汇审计与绑定架构-2026-09-15.md +++ /dev/null @@ -1,46 +0,0 @@ -# 【里程碑】AGC 资源 kind 枚举化词汇审计与绑定架构 - -| 字段 | 值 | -| --- | --- | -| Version | 1.0 | -| Status | complete | -| Date | 2026-09-15 | -| Parent Spec | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` | - -## 目标 - -在 `apps/ai-game-creator-shell` 内建立唯一的 GameCreationApp 资源 kind 领域边界:Rust enum 是权威,TypeScript 由 `ts-rs` 生成;先完成全量词汇审计和生成架构合同,再进入业务代码替换。 - -## 范围 - -- 审计 shell 内所有可能表示 GameCreationApp 资源 kind 的字段、构造器、写入边界、筛选器、资源投影、Agent 资源引用和测试 fixture,并收紧 api-server 图片快速编辑的 manifest 来源边界。 -- 以 api-server 当前仍有效的同语义 kind 作为命名与 serde 值参考,并评估 shell 当前实际生产 kind;排除 api-server legacy、billing/storage taxonomy 和其他开放领域。 -- 确认 Rust enum、`Unknown`、kebab-case JSON 和 ts-rs 生成文件的归属、生成命令与校验门禁。 -- 形成逐项 todo:当前值、真实语义、生产/测试状态、目标 enum、是否改写、验证方式。 - -## 不在范围内 - -- 不扫描或修改 api-server 其他领域的 `asset_kind`;图片快速编辑来源校验属于本次 GameCreationApp manifest 边界,必须复用共享枚举且不得保留 legacy 白名单。 -- 不改 `mediaType`、MIME、文件扩展名、`source.kind`、`source.generationKind`、任务/工作流 kind、路径名或 tracking scope。 -- manifest writer 与前端消费方已统一到共享 Rust enum/ts-rs binding;不扩展公开契约。 -- 不实现旧 manifest migration;无法解析的输入只在共享解析边界收口为 `Unknown`,由调用方拒绝或交后续归类,不增加 alias 表或 fallback。 - -## 依赖与前置条件 - -- 主规范已确认资源 kind 候选集合、`Unknown` 语义和 shell 边界。 -- `shared-contracts` 当前被 server-rs 多个 crate 使用,ts-rs 生成能力必须 feature-gated 或由独立生成入口启用,不能污染默认 SpacetimeDB/WASM 构建。 -- 当前已有 Tauri ts-rs 生成测试可作为生成命令形态参考,但不复用 UI Editor 类型目录作为资源契约目录。 - -## 验收标准 - -- [x] shell 内 manifest 资源 kind 的生产写入点、解析点、投影点和测试 fixture 已完成审计并收口。 -- [x] 每个旧值均已标注为:正式 GameCreationApp kind、其他领域字符串、legacy/错误 fallback;没有只按 grep 结果猜测的条目。 -- [x] api-server 有效值、shell 扩展值和排除值各有明确依据。 -- [x] 生成架构不会要求 server-side 默认构建安装 ts-rs。 -- [x] todo 清单的每项都有关闭条件和对应验证证据;图片快速编辑不再维护兼容白名单,退役 kind 直接失败。 - -## 证据要求 - -- 自动化:raw kind 扫描脚本/报告、Rust/TS 生成试验、serde kebab-case round-trip 试验。 -- 文档:主规范、todo 清单、下一里程碑实施计划互相链接且无冲突。 -- 边界:至少覆盖 `font`、`audio`、`sound-effect`、`background-music`、`Unknown`,以及 `source.kind`/`generationKind` 不误收编。 diff --git a/docs/project-memory/plans/【里程碑】AGC资源菜单收纳-2026-09-17.md b/docs/project-memory/plans/【里程碑】AGC资源菜单收纳-2026-09-17.md index 1c2ac43c9..48d1c9f81 100644 --- a/docs/project-memory/plans/【里程碑】AGC资源菜单收纳-2026-09-17.md +++ b/docs/project-memory/plans/【里程碑】AGC资源菜单收纳-2026-09-17.md @@ -1,7 +1,7 @@ # AGC 资源菜单收纳 - Version: 1 -- Status: implemented,本地自动化通过,待真实客户端验收 +- Status: implemented-awaiting-runtime-acceptance(本地自动化通过,待真实客户端验收) - Date: 2026-09-17 - Parent Spec: ../../technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -29,3 +29,10 @@ - 根目录类型检查与 AGC 类型检查(含 skill-pack / config 检查)通过;编码、文档索引与 diff 检查通过。 - 浏览器中真实组件预览已检查上方展开、执行回调后关闭、卡片信息入口;预览仅用演示数据,不替代真实 AGC 客户端。 - 剩余:真实客户端、原生保存对话框、触摸板操作人工验收。未推送,未创建 PR,未更新飞书。 + +## 本轮复验(2026-09-24) + +- 共用收纳控件与 UI 基元:`npx vitest run packages/shared/src/components/OverflowActions.test.tsx packages/shared/src/components/ui.test.tsx` → **14 passed**(浮层开关、外部关闭、键盘、视口约束与表格/标签等基元语义)。 +- AGC 资源画布菜单与卡面:`npx vitest run tests/resourceCanvasBottomToolbar.test.tsx tests/resourceCanvasCardName.test.tsx tests/resourceCanvasToolbarModel.test.ts`(`--root apps/ai-game-creator-shell`)→ **39 passed**。 +- 全量界面门禁:`npm run ai-game-creator-shell:check:web` → 185 files passed / 1 skipped、1806 tests passed(含工作台整表回归)。 +- 仍未验收(人工、需要真实客户端):真实客户端视觉、原生保存对话框、触摸板操作手感。 diff --git a/docs/project-memory/plans/【里程碑】AGC音频生成进入后台任务账本-2026-09-20.md b/docs/project-memory/plans/【里程碑】AGC音频生成进入后台任务账本-2026-09-20.md index e9324c283..2d25a87a2 100644 --- a/docs/project-memory/plans/【里程碑】AGC音频生成进入后台任务账本-2026-09-20.md +++ b/docs/project-memory/plans/【里程碑】AGC音频生成进入后台任务账本-2026-09-20.md @@ -49,3 +49,9 @@ AGC 功能画布音频栏目的「生成背景音乐 / 生成音效」与图片 - 自动化:AGC 前端定向 vitest(音频入口宿主生命周期、生成任务队列与侧栏、appSurface 载荷)+ Rust 定向 `cargo test`(账本与音频任务入参收口)+ 类型检查 + 编码 / 文档索引 / `git diff --check`。 - 运行时:无真实付费生成;以模拟原生接口的宿主用例覆盖提交 → 排队 → 收口 → 落卡全链。 - 边界:未受理失败的即时重开与身份复用、账本读不到 / 记录缺失的收口、跨项目切换不串任务。 + +## 本轮复验(2026-09-24) + +- 原生后台任务账本:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 asset_generation_tasks` → **15 passed / 0 failed**(任务入账、阶段投影、终态收口与事件通知路径)。 +- 前端队列与面板:`npx vitest run tests/resourceCanvasAssetGenerationQueue.test.ts tests/resourceCanvasAssetGenerationTasksPanel.test.tsx --root apps/ai-game-creator-shell` → 与批量标签同批执行通过(队列单飞、事件唤醒回退、面板状态投影)。 +- 仍未验证(需要真实平台生成与账号):真实音频生成经后台任务账本跑到终态、失败重试与跨项目切换表现。 diff --git a/docs/project-memory/plans/【里程碑】AGC项目定时快照上传-2026-09-17.md b/docs/project-memory/plans/【里程碑】AGC项目定时快照上传-2026-09-17.md index bc4889cda..7958315a6 100644 --- a/docs/project-memory/plans/【里程碑】AGC项目定时快照上传-2026-09-17.md +++ b/docs/project-memory/plans/【里程碑】AGC项目定时快照上传-2026-09-17.md @@ -1,7 +1,7 @@ # AGC 项目定时快照上传 Version: 1.0 -Status: active +Status: implemented-awaiting-runtime-acceptance Date: 2026-09-17 Parent Spec: `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的“2026-09-17 AGC 项目定时快照上传(agc-dev)” @@ -47,3 +47,13 @@ AGC 在项目打开期间按周期把用户项目增量上传到 OSS `agc-dev` - 现有 `platform_session`(用户身份与 Access Token)、项目 manifest(稳定 `project_id`)。 - 现有 `platform-oss`(PUT/HEAD、私有访问)、`api-server` 登录态中间件与 `shared-contracts`。 - 现有 AppData 私有文件写入与目录解析工具。 + +## 本轮验证(2026-09-24) + +- 客户端定向:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml project_snapshot -- --test-threads=1` → 24 passed / 1 ignored(ignored 是真实 OSS live smoke)。 +- 服务端定向:`cargo test -p api-server project_snapshot -- --test-threads=1` → 21 passed / 1 ignored(ignored 需要私有 OSS 环境文件的只读用例)。 +- 本轮补上验收标准 10 的缺口:回收选择抽成纯函数 `plan_project_snapshot_reclamation`,新增 3 条用例覆盖「只回收上一版登记过的对象」「上一版清单读不到时一张都不删」「单轮回收有上限」,并做过变异验证(把保留判据退化成只看路径时该用例变红)。 +- 主规范已补「验收面 → 用例」对照表:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的 2026-09-17 小节。 +- 仍未取得证据:真实 OSS 往返、开发态打开项目的索引写入与日志、关窗触发的那一次同步。 + +因此本计划从 `active` 改为 `implemented-awaiting-runtime-acceptance`:行为与定向测试已经落地,缺的是环境侧证据,不替用户签收。 diff --git a/docs/project-memory/plans/【里程碑】AGC首页策划补全入口-2026-09-15.md b/docs/project-memory/plans/【里程碑】AGC首页策划补全入口-2026-09-15.md deleted file mode 100644 index 04197703c..000000000 --- a/docs/project-memory/plans/【里程碑】AGC首页策划补全入口-2026-09-15.md +++ /dev/null @@ -1,20 +0,0 @@ -Version: 1 -Status: active -Date: 2026-09-15 -Parent Spec: AGC 首页与 Agent Runtime 入口 - -## 范围 - -在首页“做游戏”输入框下增加“策划补全”复选框;勾选后复用现有 `planning` 启动模式进入策划 Agent Runtime。 - -## 验收标准 - -- 仅“做游戏”显示复选框。 -- 勾选时提交 `planning`,未勾选时提交 `direct-build`。 -- “做方案”原有 `planning` 行为保持不变。 -- 切换到其它创作类型时清除游戏专属勾选状态。 - -## 不做项 - -- 不新增 runtime 类型、后端接口或持久化字段。 -- 不改变现有策划 runtime 内部流程。 diff --git a/docs/project-memory/plans/【里程碑】DirectProject Phaser迁移闭环-2026-09-14.md b/docs/project-memory/plans/【里程碑】DirectProject Phaser迁移闭环-2026-09-14.md index 54114ae05..9725dbb03 100644 --- a/docs/project-memory/plans/【里程碑】DirectProject Phaser迁移闭环-2026-09-14.md +++ b/docs/project-memory/plans/【里程碑】DirectProject Phaser迁移闭环-2026-09-14.md @@ -1,5 +1,5 @@ Version: 1.0 -Status: implemented; real-project runtime smoke pending +Status: implemented-awaiting-runtime-acceptance(真实项目 runtime smoke 待补) Date: 2026-09-14 Parent Spec: docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md diff --git a/docs/project-memory/plans/【里程碑】DirectProject Skill提及输入提示-2026-09-15.md b/docs/project-memory/plans/【里程碑】DirectProject Skill提及输入提示-2026-09-15.md deleted file mode 100644 index 77a248db4..000000000 --- a/docs/project-memory/plans/【里程碑】DirectProject Skill提及输入提示-2026-09-15.md +++ /dev/null @@ -1,43 +0,0 @@ -# 【里程碑】DirectProject Skill 提及输入提示 - -| 字段 | 值 | -| ----------- | ------------------------------------------------ | -| Version | 1.0 | -| Status | in-progress | -| Date | 2026-09-15 | -| Parent Spec | `docs/【功能说明】AGC聊天素材引用-2026-09-08.md` | - -## 目标 - -在现有 Lexical `ResourceReferenceInput` 中增加 Codex 风格 `$skill-name` 提及。用户选择 Skill 后,编辑器保留与文本相对顺序一致的原子节点;DirectProject canonical user item 保存稳定 Skill 名称,Rust 只允许当前已启用且 app-server 已发现的 Skill,并在 `turn/start` 转换为 Codex 原生 `type: "skill"` 输入项。 - -## 范围 - -- Skill 候选数据从当前 DirectProject 的已启用 Skill catalog 派生。 -- `$` typeahead 菜单、键盘选择、鼠标选择、Esc/Enter 交互与现有 `@` 菜单一致。 -- Skill inline 节点和 `content[]` 顺序恢复。 -- canonical `agc_skill_reference` part 的 ts-rs 类型、Rust 校验、历史写入与 Codex wire 转换。 -- 现有素材、运行区域、assistant、附件和工具 activity 行为保持不变。 - -## 不在范围内 - -- Skill 导入、启用、禁用、重命名和 app-server `skills/list` 生命周期改造。 -- 普通自然语言自动分类 Skill;只支持显式 `$skill-name` 选择。 -- Skill 正文预加载、Skill 内容编辑或新的权限/工具能力。 -- SpacetimeDB、HTTP API 和 assistant item 协议变更。 - -## 验收标准 - -- [ ] 输入 `$` 可显示并过滤可用 Skill,候选项显示名称和描述。 -- [ ] 选择 Skill 后插入原子 `$name` chip,文本与素材/运行区域的相对顺序保持不变。 -- [ ] canonical user item 只保存 Skill 稳定名称,不保存正文、凭据或宿主私密路径。 -- [ ] Rust 拒绝未知、禁用、未发现或名称非法的 Skill;失败时不写历史、不启动回合。 -- [ ] 合法 Skill 在 Codex wire input 中生成 `type: "skill"`、`name`、受控 `path`,顺序与 canonical content 一致。 -- [ ] 无 Skill 的旧消息、素材引用和标准 `response_item` 读取行为不变。 - -## 证据要求 - -- 前端:Lexical 草稿顺序、候选过滤、chip 原子性与 `$`/`@` 共存测试。 -- Rust:模型序列化、Skill catalog 校验、wire 转换、失败关闭和历史重放测试。 -- 运行时:DirectProject app-server smoke(环境可用时)。 -- 门禁:相关 Vitest、AGC Rust 定向测试、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check`。 diff --git a/docs/project-memory/plans/【里程碑】DirectProject Thread Manager事件订阅-2026-09-15.md b/docs/project-memory/plans/【里程碑】DirectProject Thread Manager事件订阅-2026-09-15.md deleted file mode 100644 index 35fe7222c..000000000 --- a/docs/project-memory/plans/【里程碑】DirectProject Thread Manager事件订阅-2026-09-15.md +++ /dev/null @@ -1,53 +0,0 @@ -# 【里程碑】DirectProject Thread Manager 事件订阅 - -| 字段 | 值 | -| ----------- | -------------------------------------------------------------------------------- | -| Version | 1.0 | -| Status | ready | -| Date | 2026-09-15 | -| Parent Spec | `docs/technical/【技术方案】DirectProject Codex原始历史与异常恢复-2026-09-04.md` | - -## 目标 - -让 DirectProject 对话在页面离开、重进和短暂断线后仍能由前端重建运行态;运行态事件由 Tauri 进程级 Thread Manager 管理,已完成 item 继续以 `project.jsonl` 为持久化事实源。 - -## 范围 - -- 每 thread 一个全局 seq 和 append-only replay queue。 -- 每 subscriber 独立的 Rust 内部 cursor、并发安全消费和 notify 唤醒。 -- `subscribe` bootstrap、`consume`、`SUBSCRIPTION_EXPIRED` 和历史 item 锚点。 -- app-server 公开事件的安全标准化、item 持久化先于完成事件转发。 -- 前端 raw event reducer、历史懒加载和过期重订阅。 -- 删除本链路 legacy conversation 格式支持,不提供 fallback 或 migration。 - -## 不在范围内 - -- SpacetimeDB、HTTP API、Codex thread durable recovery。 -- 新的 item durable/status/pendingInteraction 字段或持久化确认事件。 -- 前端访问 JSONL 路径、格式或持久化细节。 -- 多 active turn;同一 thread 仍只有一个 active turn。 - -## 依赖与前置条件 - -- DirectProject 现有 app-server 事件解析和 `project.jsonl` 读写。 -- 当前 Tauri command/event 注册入口。 -- 现有前端 DirectProject 聊天 reducer 与历史加载入口。 - -## 验收标准 - -- [ ] 页面离开后 app-server 回合继续,重进页面能通过 subscribe 重建 unfinished item。 -- [ ] 同一 thread 的多个 subscriber 各自消费,不互相覆盖或重复推进 cursor。 -- [ ] `consume` 返回 cursor 之后的全局 raw events,通知不携带 payload。 -- [ ] queue eviction 只清理队头;落后 subscriber 得到 `SUBSCRIPTION_EXPIRED` 并可重新 subscribe。 -- [ ] item 完成先持久化,成功后才进入完成事件队列;失败不发送正常完成事件。 -- [ ] `turn.completed` 由 app-server 终态进入 raw queue,前端据此结束运行态。 -- [ ] subscribe 返回 item 历史锚点而不是完整 history;前端可按 itemId 懒加载。 -- [ ] 未完成 item 的每个 delta 可从 `item.started` 开始重放;不截断 active item。 -- [ ] legacy conversation 行直接失败关闭,无 fallback、无迁移。 -- [x] DirectProject 首页历史切片存在 `hasMore` 时,即使当前可见窗口没有隐藏消息,也提供按钮和滚动两种“显示更早”入口。 - -## 证据要求 - -- 自动化:queue/cursor/eviction 并发单测、事件标准化和持久化顺序测试、Tauri command 测试、前端 reducer 与重订阅测试。 -- 运行时:关闭/切页后重进 DirectProject;并发 item;短暂断线 consume;cursor 过期重订阅。 -- 边界:持久化失败、未知 subscription、queue 超限、多个 subscriber、turn 无 item 间隙、legacy 行拒绝。 diff --git a/docs/project-memory/plans/【里程碑】DirectProject canonical content严格边界-2026-09-16.md b/docs/project-memory/plans/【里程碑】DirectProject canonical content严格边界-2026-09-16.md deleted file mode 100644 index ffd7767f8..000000000 --- a/docs/project-memory/plans/【里程碑】DirectProject canonical content严格边界-2026-09-16.md +++ /dev/null @@ -1,51 +0,0 @@ -# 【里程碑】DirectProject canonical content 严格边界 - -| 字段 | 值 | -| ----------- | ------------------------------------------------ | -| Version | 1.0 | -| Status | implemented | -| Date | 2026-09-16 | -| Parent Spec | `docs/【功能说明】AGC聊天素材引用-2026-09-08.md` | - -## 目标 - -让 DirectProject 的用户消息只以 `content[]` 作为 canonical 输入:转换函数原样传递编辑器草稿的 content part,不做二次预过滤;只在最终 content 上判断是否存在有效输入;所有 Direct Codex caller 必须显式提供完整 `userItem`。 - -## 范围 - -- 移除 `chatComposerDraftToDirectCodexUserItem` 对纯空白 `input_text` 的预过滤。 -- Direct Codex 发送前只做最终 content 的有效性判断,不改写 content。 -- 删除 `executeChatAgentReply` 在 `userItem` 缺失时的构造兜底。 -- 删除 `ChatComposerDraft` 的 `text` / `references` 字段,草稿只保留 canonical `content`。 -- 修正首页首轮、队列出队和其它 Direct Codex caller,使其直接构造 canonical user item。 -- 将队列与策略确认重试按 canonical user item 传递,避免拆回 `text` / `references`。 -- 仍在使用的旧 Supervisor/Planning caller 保持非 Direct Codex 行为,并添加后续迁移 TODO。 - -## 不在范围内 - -- 不保留从 `draft.text` / `draft.references` 重建 Direct Codex content 的兼容分支。 -- 不新增断言 legacy 字段“不存在”的测试;现有测试直接迁移到 content-only 输入。 -- 不修改 Rust user item schema、SpacetimeDB schema、HTTP API 或历史迁移。 - -## 验收标准 - -- `chatComposerDraftToDirectCodexUserItem` 输出与输入 `draft.content` 顺序和值完全一致。 -- 只有当最终 content 不含非空文本且不含任何非文本 part 时,发送入口才拒绝本轮。 -- Direct Codex 路径不存在 `userItem ?? ...` 或等价 fallback。 -- `ChatComposerDraft` 只有 `content` 一个字段;`text` / `references` 不再是草稿契约的一部分。 -- 首页首轮、普通聊天、队列出队、策略确认重试均发送同一个 canonical user item 语义。 -- 旧 Supervisor/Planning caller 上有明确 TODO,且不进入 Direct Codex canonical 发送路径。 - -## 实现结论 - -- 前端不再做任何空白过滤:Lexical 投影层原样透传编辑器节点,段落分隔符(root 子节点之间补的 `\n`)、软换行、chip 后的分隔空格都各自成 part,既不丢弃也不与相邻 part 合并 —— 前端不替用户改写他输入的内容。 -- 有效输入只判整条 content:有一段非空白文本或任何一个非文本 part 就算有效输入,单个纯空白 `input_text` 合法。前端 `hasMeaningfulDirectCodexContent` 与 Rust `validate_direct_codex_user_item`(`content_has_meaningful_input`)同口径,Rust 侧不再逐个 part 拒绝空文本;`wire.rs` 的「不能转换为空 prompt」只作兜底。 -- 显示文本、队列 chip 文案、草稿持久化和润色判据统一由 `directCodexContentToPromptText(content, assets)` 从 content 派生,不再维护并行的 `text` 字段;`assets`(当前项目 manifest)必填,`agc_resource_reference` 按 `@显示名` 展开,消息正文与队列 chip 因此逐字一致。 -- 需要文本草稿的旧入口(`replaceText`、快速编辑)仍由编辑器把文本 + 引用重建为 content,方向是「文本 → content」,不存在「legacy 字段 → content」的回退。 - -## 证据 - -- `apps/ai-game-creator-shell/tests/resourceReferences.test.ts`:content 原样传递、空白 part 保留、有效性判断、文本派生。 -- `apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx`(含「引用后面的段落分隔原样落进 content」)、`chatPromptPolish.test.tsx`、`tests/appSurface/*.suite.ts`:草稿读取、提醒判据、队列与 caller 迁移到 content-only,并按逐字投影断言 content。 -- `apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/`:`validation.rs` 的「只有整条 content 全空白才算空输入」与 `wire.rs` 的「单个纯空白 part 通过校验、整条全空白拒绝」用例。 -- AGC shell 类型检查、定向 Vitest、`npm run check:encoding`、`git diff --check` 通过。 diff --git a/docs/project-memory/plans/【里程碑】DirectProject composer canonical content闭环-2026-09-21.md b/docs/project-memory/plans/【里程碑】DirectProject composer canonical content闭环-2026-09-21.md deleted file mode 100644 index 27676fa19..000000000 --- a/docs/project-memory/plans/【里程碑】DirectProject composer canonical content闭环-2026-09-21.md +++ /dev/null @@ -1,65 +0,0 @@ -# 【里程碑】DirectProject composer canonical content 闭环 - -| 字段 | 值 | -| ----------- | --- | -| Version | 1.0 | -| Status | implemented | -| Date | 2026-09-21 | -| Parent Spec | `docs/【功能说明】AGC聊天素材引用-2026-09-08.md` | -| Related ADR | `docs/adr/【ADR】DirectProject独立聊天容器与工作台钱包布局-2026-09-18.md` | -| Supersedes | `docs/project-memory/plans/【实施计划】DirectProject canonical content严格边界-2026-09-16.md` 的已实现边界清理,补齐其遗漏的编辑器回写路径 | - -## 问题确认 - -上一里程碑把 Direct 发送、队列和 Rust user item 收口到了 `content[]`,但输入编辑器仍保留一条旧的派生状态接口: - -- `ChatComposerDraft` 仍包含 `text`、`references`、`content` 三个字段。 -- `ResourceReferenceInput` 仍接收 `value` + `references`,并在受控同步 effect 中调用 `applyDraftToRoot(value, references)`。 -- `replaceText` 与 `usePromptPolish` 的 `applyPromptText` 也调用 `applyDraftToRoot(text, current.references)`。 -- `applyDraftToRoot` 只重建文本和 `ChatReference` 节点,不能表达 `agc_attachment_reference`,会在任何包含附件节点的 editor root 重建中丢附件。 -- Direct controller 仍把同一份 `content` 拆成 `chatContent`、`chatInput`、`chatReferences` 三份状态;提交时又把附件 sidecar 追加回 `content`,导致编辑器 canonical content 与本轮完整 canonical user content 不是同一份事实源。 - -## 目标 - -让 DirectProject 的 composer 从读取、润色、受控恢复、队列、附件到提交都只围绕一份有序 `content[]` 运作: - -1. 编辑器对外草稿类型只有 `content`。 -2. 文本展示、提醒、队列 chip 和 prompt 参数全部由 `content[]` 派生。 -3. 任意编辑器回写只能接收完整 `content[]`;不能用文本和引用列表重建 root。 -4. `agc_attachment_reference` 在恢复、润色回写、队列和提交中保持顺序和值,不得丢失、搬移或重复。 -5. DirectProject 不再维护 `chatInput` / `chatReferences` / `chatContent` 并行事实源;待发上传附件也必须在进入提交前显式合并为同一 canonical content。 - -## 边界与非目标 - -- 保留 `directCodexContentToPromptText` 作为只读展示投影,不把它反向解析成 content。 -- 保留 `ChatReference` 作为 picker/UI 的候选与节点显示模型;它不是 Direct 草稿或发送模型。 -- Planning V2 与资源快速编辑若仍需要文本 props,只能通过明确的 adapter/独立表象接口接入,不能让这些 legacy props 继续成为 Direct composer 的接口。 -- 不修改 Rust user item schema、SpacetimeDB、HTTP API 或附件协议字段。 -- 不引入兼容 alias、`text + references → content` fallback、隐式附件 sidecar 拼接或双写状态。 - -## 验收标准 - -- `ChatComposerDraft`、`ResourceReferenceInput` 的 Direct 使用面和 Direct composer props 不再暴露 `text` / `references` 双轨草稿。 -- 代码中不存在 Direct 路径对 `applyDraftToRoot(value, references)`、`replaceText(text)` 或等价 legacy 重建器的调用。 -- `content[]` 中交错的文本、资源引用、运行区域引用、Skill 和附件经过:初始恢复 → 读取 → 润色回写 → 再读取,part 一个不少。 -- 润色回包还留着 `@显示名` / `$名称` / `@附件名` 时,对应 chip 在原位置复活;token 被整体改写掉的 part 补在末尾,不丢。 -- 附件-only、文本+附件、资源引用+附件、文本+资源引用+附件四类提交均只生成一份 canonical user item,附件字段完整保留。 -- 队列入队、出队、策略确认重试复用同一份 `userItem.content`,不从 prompt 文本重建。 -- Direct 提交清理草稿后,待发附件和 editor content 同时清空;失败或取消不会悄悄丢失待发附件。 -- Planning/快速编辑的迁移或隔离有明确类型接口和定向测试,不再借 Direct 的双轨 props。 - -## 证据要求 - -- ResourceReferenceInput 纯投影/回写测试:包含附件节点的 round-trip 与润色回写不丢附件。 -- Direct composer appSurface:四类 content 组合、队列、策略重试及清理语义。 -- 类型检查、定向 Vitest、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check`。 - -## 落地结果 - -- `ChatComposerDraft` 只剩 `content`;`ResourceReferenceInput` 的对外接口是 `initialContent` + `onChange` + `getDraft()`,受控 `value` / `references` 与 `applyDraftToRoot` 已删除。 -- 编辑器 root 回写只剩 `applyContentToRoot`(完整 content,含附件)一条路径;清空、初始恢复、润色回写都走它。 -- Direct composer 提交时把 editor content 与待发附件 sidecar 合成同一份 canonical content;controller 不再持有 `chatInput` / `chatReferences` / `chatContent`。 -- Planning 提交与 legacy 消费方通过单向 `directCodexContentToLegacyContentDto` 取文本,不回写编辑器。 -- 润色回写(`applyPolishedTextToRoot`)对引用与附件用同一套 token 扫描(`draftScanToken`):token 存活则原位换回真 part,被改写的 part 末尾补位;附件不再丢出 canonical content。 -- 遗留 TODO:润色服务整体改写文本、连 token 一起删掉时,前端无法反推原位置,只能末尾补位;需要精确恢复时由产品补带位置信息的润色协议。 -- 收口扩展(2026-09-21,栏目画布图片类生成浮层):面板 state、重开草稿 `ResourceCanvasAssetGenerationPanelDraft`、重试身份判据与提交载荷全部只有一份 `content[]`;`directCodexContentToLegacyContentDto` 只在任务落账这一个出站边界派生,账本回草稿走同一套 token 反解析(`legacyContentDtoToContent`)。token 扫描实现从 `ResourceReferenceInput` 提到 `resourceReferences`,润色回写与 legacy 翻译共用一份;无从解析的资源引用合成 `kind: unknown` 占位而不再被静默丢弃。详见 `decision-log.md` 同名条目。 diff --git a/docs/project-memory/plans/【里程碑】DirectProject用户ResponseItem输入-2026-09-15.md b/docs/project-memory/plans/【里程碑】DirectProject用户ResponseItem输入-2026-09-15.md deleted file mode 100644 index 5e1e9fa1d..000000000 --- a/docs/project-memory/plans/【里程碑】DirectProject用户ResponseItem输入-2026-09-15.md +++ /dev/null @@ -1,51 +0,0 @@ -# 【里程碑】DirectProject 用户 Response item 输入 - -| 字段 | 值 | -| ----------- | ------------------------------------------------ | -| Version | 1.0 | -| Status | proposed | -| Date | 2026-09-15 | -| Parent Spec | `docs/【功能说明】AGC聊天素材引用-2026-09-08.md` | - -## 目标 - -将 DirectProject 的用户消息升级为受限 Response API `message` item:文本与 AGC 引用按编辑顺序内联,Rust 校验后持久化 canonical item,并转换为 Codex 可接受的输入。 - -## 范围 - -- Rust 定义 user item 与 content part,并通过 `ts-rs` 生成 TypeScript 绑定。 -- 前端 Lexical 草稿生成 inline `content[]`。 -- `agc_resource_reference` 只使用稳定 `resourceId`。 -- `agc_runtime_region_reference` 保留运行区域语义摘要。 -- Rust 在持久化前完成白名单、manifest 与路径校验。 -- 现有标准 `response_item` 原样兼容;legacy conversation 行不提供 fallback。 -- 保持 assistant 返回、工具 activity 与上传 DTO 不变;DirectProject canonical user item 不再保存附件 sidecar,所有本地上传文件(包括图片)统一作为 `content[]` 中按顺序排列的 `agc_attachment_reference`。 - -## 不在范围内 - -- assistant item 前端投影或 Tauri 返回值改造。 -- 工具 item、reasoning、file change、MCP item 的 UI 模型化。 -- 不新增图片专用 content part;上传 DTO 只作为输入适配,不作为历史事实源。 -- SpacetimeDB schema 或 HTTP API 变更。 - -## 依赖与前置条件 - -- DirectProject 现有 app-server thread/inject_items/turn/start 链路。 -- 项目 manifest 作为资源身份与路径权威。 -- 现有 `project.jsonl` 的 `response_item` envelope。 - -## 验收标准 - -- [x] 前端生成的 canonical user item 保留 Lexical 中文本与引用的相对顺序。 -- [x] `agc_resource_reference` 仅包含 `resourceId`,显示信息由 manifest 派生。 -- [x] runtime-region 字段经过 Rust 有界清洗并验证关联资源。 -- [x] 未知 part、失效资源或非法路径在持久化前失败关闭。 -- [x] canonical item 以 `response_item` 写入历史,标准旧 item 原样可读。 -- [x] Codex wire input 不含 AGC 私有 part,且顺序与 canonical content 一致。 -- [x] assistant、附件和工具链路行为无变化;所有上传文件按 content 顺序内联,附件-only 输入也能进入 DirectProject prompt。 - -## 证据要求 - -- 自动化:Rust item 校验/转换/历史测试;前端草稿顺序与类型测试;ts-rs 生成检查。 -- 运行时:DirectProject 本地 app-server smoke(如环境可用)。 -- 边界:未知 part、资源删除、非法路径、重复提交 clientTurnId、legacy 行拒绝。 diff --git a/docs/project-memory/plans/【里程碑】DirectProject聊天模块抽离-2026-09-18.md b/docs/project-memory/plans/【里程碑】DirectProject聊天模块抽离-2026-09-18.md deleted file mode 100644 index bbb5e275e..000000000 --- a/docs/project-memory/plans/【里程碑】DirectProject聊天模块抽离-2026-09-18.md +++ /dev/null @@ -1,50 +0,0 @@ -# 【里程碑】DirectProject 聊天模块抽离 - -| 字段 | 值 | -| ----------- | ---------------------------------------------------------------------- | -| Version | 1.0 | -| Status | proposed | -| Date | 2026-09-18 | -| Parent Spec | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` | - -## 目标 - -把普通项目的 DirectProject 聊天从 `App.tsx` 与工作台聊天宿主中抽出为独立产品容器(`view/project-development/chat/`),并把项目级钱包入口提升到工作台布局层;立项策划(Design Agent、Planning V2)随后收敛到 `view/project-development/planning/`。 - -## 范围 - -- 公开入口只有一个 `DirectProjectChat`;内部可按状态、订阅/历史、发送/队列、附件和表现职责拆成私有模块。 -- DirectProject 容器拥有项目对话历史、运行态事件、聊天投影、首屏锚点、历史分页、发送回合、FIFO 队列、附件、中止和项目切换清理。 -- `App.tsx` 保留通用项目壳状态,只传窄项目上下文与布局同步出口;不再拥有 Direct 专属 state/ref/effect/handler。 -- 立项策划只由 `PlanningChatView` 承载;共享 Composer、消息、Markdown、工具卡片和通用设置表现可以复用,但不共享产品行为容器。 -- 钱包入口由项目工作台布局(`ProjectDevelopmentView` 的布局级头部/工具栏)独立渲染,不进入聊天上下文或聊天设置浮层。 - -## 不在范围内 - -- 不改变 DirectProject 的 Tauri/Rust 命令、DTO、Thread Manager、Codex app-server、持久化事实源或运行态事件语义。 -- 不改变 DirectProject 的路由选择条件、发送/队列/附件/中止/历史锚点/投影行为;钱包仅按已确认的布局归属调整。 -- 不合并 DirectProject、Design Agent、Planning V2;不新增通用 Agent 聊天框架。 -- 不新增测试场景或 Provider E2E;现有测试按新模块所有权迁移。 -- 不保留 Direct 旧条件分支、alias、feature flag、双跑或兼容 fallback。 - -## 依赖与前置条件 - -- 现有 DirectProject 真相源收敛与 Thread Manager 事件订阅已作为当前行为合同。 -- 现有 DirectProject 纯模块测试与 `chat-composer.suite.ts`、`project-development.suite.ts` 页面断言作为迁移基线。 -- `ProjectDevelopmentView` 已是钱包插槽注入与项目布局的外层边界,可移除向聊天元素的 `cloneElement` 注入。 - -## 验收标准 - -- [x] DirectProject 只通过独立 `DirectProjectChat` 入口渲染,不再作为工作台聊天宿主里的条件分支。 -- [ ] DirectProject 的订阅、历史、投影、发送、队列、附件、中止和项目切换状态不再由 `App.tsx` 持有。 -- [x] Design Agent 与 Planning V2 的入口和行为不被 Direct 抽离改变(策划链路已在后续变更中收敛到 `PlanningChatView`)。 -- [ ] 钱包入口由项目工作台布局独立渲染,聊天组件和聊天设置不接收或渲染 `walletEntry`。 -- [ ] 现有 DirectProject 测试断言按新模块所有权迁移,测试场景与覆盖范围不减少,也不新增场景。 -- [ ] 代码中不存在 Direct 旧 fallback、feature flag、兼容 alias 或共享行为条件分支。 - -## 证据要求 - -- 自动化:迁移后的 Direct 纯模块测试、现有 Composer/项目开发页面测试、非 Direct 现有测试与 TypeScript 检查。 -- 文档:`npm run check:doc-index`、`npm run check:encoding`、`git diff --check`。 -- 边界:Thread Manager 订阅回执竞态、首屏锚点、历史连拉、实时/历史合并、FIFO 出队、附件清理、中止 released 分支和项目切换。 -- 未验证项:真实 Provider/app-server 运行时不因本次结构重构新增验收范围;若现有环境无法运行,记录为未验证而不添加替代兼容路径。 diff --git a/docs/project-memory/plans/【里程碑】DirectProject聊天真相源收敛-2026-09-16.md b/docs/project-memory/plans/【里程碑】DirectProject聊天真相源收敛-2026-09-16.md index 0a1ebbe3d..f20e8da83 100644 --- a/docs/project-memory/plans/【里程碑】DirectProject聊天真相源收敛-2026-09-16.md +++ b/docs/project-memory/plans/【里程碑】DirectProject聊天真相源收敛-2026-09-16.md @@ -3,7 +3,7 @@ | 字段 | 值 | | ----------- | -------------------------------------------------------------------------------- | | Version | 1.0 | -| Status | implemented(自动化验收通过,运行时验收待补) | +| Status | implemented-awaiting-runtime-acceptance | | Date | 2026-09-16 | | Parent Spec | `docs/technical/【技术方案】DirectProject Codex原始历史与异常恢复-2026-09-04.md` | diff --git a/docs/project-memory/plans/【里程碑】Direct三维请求自选技术栈-2026-09-16.md b/docs/project-memory/plans/【里程碑】Direct三维请求自选技术栈-2026-09-16.md index d74bf02bc..e1bf24863 100644 --- a/docs/project-memory/plans/【里程碑】Direct三维请求自选技术栈-2026-09-16.md +++ b/docs/project-memory/plans/【里程碑】Direct三维请求自选技术栈-2026-09-16.md @@ -1,5 +1,5 @@ Version: 1.0 -Status: implemented; real-project runtime smoke pending +Status: implemented-awaiting-runtime-acceptance(真实项目 runtime smoke 待补) Date: 2026-09-16 Parent Spec: docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md diff --git a/docs/project-memory/plans/【里程碑】Direct回合跨页面生命周期与运行中项目可见性-2026-09-15.md b/docs/project-memory/plans/【里程碑】Direct回合跨页面生命周期与运行中项目可见性-2026-09-15.md index 3394c4fe6..9031a89dc 100644 --- a/docs/project-memory/plans/【里程碑】Direct回合跨页面生命周期与运行中项目可见性-2026-09-15.md +++ b/docs/project-memory/plans/【里程碑】Direct回合跨页面生命周期与运行中项目可见性-2026-09-15.md @@ -1,7 +1,7 @@ # 【里程碑】Direct回合跨页面生命周期与运行中项目可见性-2026-09-15 Version: 1 -Status: in-progress +Status: implemented-awaiting-runtime-acceptance Date: 2026-09-15 Parent Spec: `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`「2026-09-15 Direct 回合跨页面生命周期与运行中项目可见性」 @@ -31,3 +31,13 @@ Parent Spec: `docs/technical/【技术方案】AI游戏创作智能体App实施 - “离开页面即取消”仍是未采纳的另一种语义;本轮只实现后台继续。 - 应用重启后的“未完成回合”恢复不在本里程碑范围(回合注册表是进程内状态);若未来要求跨重启恢复,需要另立里程碑并定义持久化身份与对账合同。 - 面板是否需要展示非 Direct(专业 Agent / 策划 Agent)运行中的项目,本轮不做;先把 Direct 回合这条事实链路做正确。 + +## 本轮验证(2026-09-24) + +- Rust 定向:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 direct_active_turn` → `read_direct_active_turn_reports_the_registered_turn_and_disappears_after_drop` 通过(登记可见、guard drop 后消失)。 +- 前端定向:`npx vitest run tests/directActiveTurns.test.tsx tests/agentRuntimeModel.test.ts` → 29 passed(快照读取、单飞刷新、事件订阅、失败保留、报错归类)。 +- 全量界面门禁(含 appSurface):`npm run ai-game-creator-shell:check:web` → 185 files passed / 1 skipped,1806 tests passed。 +- 计划里写的「快照轮询」没有留在产品运行时:`src/features/agent-runtime/directActiveTurns.ts` 走 `DIRECT_ACTIVE_TURNS_CHANGED_EVENT` 事件唤醒 + 单飞读取,事件桥不可用时只做一次启动快照,不恢复定时轮询。 +- 仍未取得证据(需要真实运行):真机重新进入正在跑的项目后恢复忙碌态与进度、标题栏入口点击进入对应项目、回合结束后可再次发送。 + +因此本计划从 `in-progress` 改为 `implemented-awaiting-runtime-acceptance`:代码与定向测试已落地,缺的是真机运行时证据。 diff --git a/docs/project-memory/plans/【里程碑】Provider推理与正文分离及策划Agent展示-2026-09-14.md b/docs/project-memory/plans/【里程碑】Provider推理与正文分离及策划Agent展示-2026-09-14.md index bd9e3124d..752aa67f2 100644 --- a/docs/project-memory/plans/【里程碑】Provider推理与正文分离及策划Agent展示-2026-09-14.md +++ b/docs/project-memory/plans/【里程碑】Provider推理与正文分离及策划Agent展示-2026-09-14.md @@ -3,7 +3,7 @@ | 字段 | 值 | | ------------- | ------------------------------------------------------------------------ | | Version | 1.0 | -| Status | in-progress | +| Status | implemented-awaiting-runtime-acceptance | | Date | 2026-09-14 | | Parent Spec | `docs/technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md` | | Related Issue | `GenarrativeAI/Genarrative#331` | @@ -212,3 +212,11 @@ git diff --check ## 当前状态与下一步 当前已完成 Provider 解析、策划 Runtime 生命周期、历史 reasoning 恢复及响应顺序归属修复;待本轮提交后继续按定向回归结果推进后续验收。字段语义、默认关闭策略、Responses 事件覆盖范围和 reasoning 不进入普通上下文的约束保持不变。 + +## 本轮复核(2026-09-24) + +计划自身写的「当前已完成 Provider 解析、策划 Runtime 生命周期、历史 reasoning 恢复及响应顺序归属修复;待本轮提交后继续按定向回归结果推进后续验收」在本轮已补齐定向回归证据: + +- `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml design_runtime::tests -- --test-threads=1` → **24 passed / 0 failed**,含 `design_request_enables_reasoning_capture_only_for_design_runtime`(只有策划 Runtime 打开 reasoning 捕获)、`persisted_reasoning_follows_response_order_across_tool_only_responses`(跨 tool-only 响应的响应顺序归属)、`persisted_reasoning_stays_with_the_turn_before_an_approval_boundary`、`scripted_design_provider_emits_reasoning_without_persisting_it`、`scripted_design_provider_retry_clears_previous_reasoning_attempt`。 +- 前端展示沿用默认折叠的思考区域(`PlanningChatView` 消费 `message.reasoningText` 与 reasoning 条目),界面套件在 `npm run ai-game-creator-shell:check:web`(185 files / 1806 tests passed)内全绿。 +- 未验证(需要真实 Provider):真实流式回合里 reasoning 与正文分离、历史恢复与多段合并的端到端表现。 diff --git a/docs/project-memory/plans/【里程碑】UI设计文档引用代码上下文-2026-09-14.md b/docs/project-memory/plans/【里程碑】UI设计文档引用代码上下文-2026-09-14.md index 2b7d92220..7a4f5df5e 100644 --- a/docs/project-memory/plans/【里程碑】UI设计文档引用代码上下文-2026-09-14.md +++ b/docs/project-memory/plans/【里程碑】UI设计文档引用代码上下文-2026-09-14.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Version | 1 | -| Status | in-progress | +| Status | implemented-awaiting-runtime-acceptance | | Date | 2026-09-14 | | Parent Spec | `docs/【技术方案】UI工作流资源桥接与Runtime执行-2026-08-24.md` | @@ -35,15 +35,29 @@ ## 验收标准 -- [ ] UI 编辑器 JSON 资源创建、加载、保存、workflow 校验和引用分支均只接受 `ui-design-doc + application/json`。 -- [ ] Direct Codex 成功引用 UI 文档时,prompt 追加 `请先阅读生成的带有文档的代码片段: {relative_path}`。 -- [ ] UI 文档生成失败时,prompt 保留原 metadata 并追加 `生成代码遇到错误{error}`,不走图片或其它文件 fallback。 -- [ ] `ui-prototype` 图片引用不触发 UI 文档代码生成。 -- [ ] 多个引用按顺序处理,单个 UI 文档失败不丢失其它引用。 -- [ ] Rust/TypeScript kind 映射一致,旧 kind 不被隐式迁移。 +- [x] UI 编辑器 JSON 资源创建、加载、保存、workflow 校验和引用分支均只接受 `ui-design-doc + application/json`。 +- [x] Direct Codex 成功引用 UI 文档时,prompt 追加 `请先阅读生成的带有文档的代码片段: {relative_path}`。 +- [x] UI 文档生成失败时,prompt 保留原 metadata 并追加 `生成代码遇到错误{error}`,不走图片或其它文件 fallback。 +- [x] `ui-prototype` 图片引用不触发 UI 文档代码生成。 +- [x] 多个引用按顺序处理,单个 UI 文档失败不丢失其它引用。 +- [x] Rust/TypeScript kind 映射一致,旧 kind 不被隐式迁移。 ## 证据要求 - 自动化:persistence、direct_codex_user_item、shared contract 定向测试;`cargo fmt --check`、`npm run check:encoding`、`git diff --check`。 - 运行时:不要求真实 Provider;测试验证生成文件路径、renderer 文档注释和 prompt 注入结果。 - 边界:旧 kind、图片 kind、损坏 JSON、renderer 错误、多引用和路径来源均有测试。 + +## 本轮复核(2026-09-24) + +- 身份与词表已落地:`server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs` 有 `UiDesignDoc => "ui-design-doc"`,生成的 TS union 同步包含 `ui-design-doc`;旧 `UI` / `ui` / `ui-design` 没有解析入口,也没有兼容 fallback。 +- 代码上下文注入已落地:`agent/direct_codex_user_item/wire.rs` 命中 `ui-design-doc` + `application/json` 时调用 `generate_ui_design_code_at`,成功追加生成代码路径、失败追加原始生成错误,其它引用不受影响;决策记录见 `decision-log.md` 的 2026-09-14 与 `ui-design-doc` 词表条目。 +- 定向测试(本轮实跑):`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 direct_codex_user_item::` → **33 passed / 0 failed**,含生成代码路径注入与「生成代码遇到错误」两条断言。 +- 未验证(需要真实 Provider 回合):在真实 Direct Codex 回合里引用 UI JSON 文档后,模型确实按注入的生成代码路径工作。 + +## 逐条勾选依据(2026-09-24) + +- 条目 1:`ui_editor/persistence.rs` 的 `ui_design_asset`(kind + mediaType 双校验)、`workflow.rs` 两处门禁与 `resource_bridge.rs` 的 `ui-design-doc + application/json` 判定;用例 `json_preview_recognizes_registered_json_and_editor_requires_canonical_kind`(`Document` 种类下读写均失败)与 `ordinary_or_foreign_json_preview_never_grants_ui_editing_or_overwrites_content`。 +- 条目 2/3/4:`wire.rs` 的 `ui_design_doc_reference_appends_generated_code_context`、`ui_design_generation_failure_keeps_reference_and_reports_error`、`other_asset_kind_reference_does_not_generate_ui_design_code`(`cargo test … direct_codex_user_item::` → 34 passed)。 +- 条目 5:本轮新增用例 `multiple_references_keep_order_when_one_ui_design_doc_generation_fails`(UI 文档生成失败时仍保留引用顺序与其它引用,且不出现代码片段指引)。 +- 条目 6:kind 唯一真源在 `shared-contracts` 的声明表与 ts-rs 生成的 union;解析只有严格入口 `parse_with_context`,无别名表、无隐式迁移(见 decision-log 的 kind 单源条目)。 diff --git a/docs/project-memory/plans/【里程碑】后台模板管理-2026-09-19.md b/docs/project-memory/plans/【里程碑】后台模板管理-2026-09-19.md index 3346e9501..cbfd83e93 100644 --- a/docs/project-memory/plans/【里程碑】后台模板管理-2026-09-19.md +++ b/docs/project-memory/plans/【里程碑】后台模板管理-2026-09-19.md @@ -61,3 +61,9 @@ OSS index 单一真相,active/inactive 两组;CLI/Rust 共用不可变对象 - 后台 DTO 只携带名称/简介/标签/上下架/封面/expectedRevision,结构上无法改动 ZIP、版本或其它模板,符合「ZIP 与版本不变、其他模板与未知字段保留」;未知字段保留由 `module-assets` 的 metadata 往返用例证明。 - 封面公共域名在 api-server 侧是常量 `https://agc-dev.oss-rg-china-mainland.aliyuncs.com/`,与「模板库固定位于 `agc-dev` bucket」的既有合同一致(客户端也只信任该主机,可用 `AGC_TEMPLATE_LIBRARY_BASE_URL` 覆盖但仍限于该主机);存储适配器在发现配置的 bucket/endpoint 不是该组合时直接失败关闭,因此不存在「读到别处清单」的路径。若将来模板库换 bucket,这三处必须一起改。 - 「页面迟到响应失败关闭」由 `readGeneration` 计数 + `AbortController` 实现(卸载、token 切换、写后重载都会作废旧响应);刷新按钮在读取中禁用,因此不存在用户可触发的并发同 token 刷新,该判据由既有「token 切换后忽略旧列表和未确认写操作」与 409 用例覆盖,无需新增用例。 + +## 本轮复验(2026-09-24) + +- 模板管理页与上传入口所在的 `AdminAgcTemplatesPage`:修复上传弹窗表头的错误元素(`TableHeader` 当 `` 用导致嵌套 `thead`),新增 1 条列头角色/层级回归用例;`AdminAgcTemplatesPage.test.tsx` 21 项、含 `adminApiClient.test.ts` 共 36 项通过。 +- 后台契约与领域规则复跑:`module-assets` 的 `template_library` 11 项、`api-server` 的 `agc_template` 路由权限用例通过;`npm run admin-web:typecheck` 通过。 +- 仍未执行:真实 dev bucket 写入(按验收口径只在替身/只读路径验证)。 diff --git a/docs/project-memory/plans/【里程碑】图集切片模式显式决策-2026-09-17.md b/docs/project-memory/plans/【里程碑】图集切片模式显式决策-2026-09-17.md index cea92f936..48d752c63 100644 --- a/docs/project-memory/plans/【里程碑】图集切片模式显式决策-2026-09-17.md +++ b/docs/project-memory/plans/【里程碑】图集切片模式显式决策-2026-09-17.md @@ -3,7 +3,7 @@ | 字段 | 值 | | ----------- | ------------------------------------------------------- | | Version | 1.0 | -| Status | proposed | +| Status | implemented-awaiting-runtime-acceptance | | Date | 2026-09-17 | | Parent Spec | `docs/【编辑器】画板图标素材生成入口设计-2026-06-15.md` | @@ -34,16 +34,35 @@ ## 验收标准 -- [ ] 省略 / `null` / 空字符串 `sliceMode` 的图集生成请求在定价、入队、扣费和 provider 调用之前返回 `400`,错误体含 `field=sliceMode`。 -- [ ] `grid` 缺 `gridX` 或 `gridY`、越界、乘积超限时 `400`;`connected-components` 携带 `gridX`/`gridY` 时 `400`。 -- [ ] 公开契约、MCP / Agent 工具说明、Skill 与画板前端类型都要求显式声明,且不再声明任何默认值。 -- [ ] AGC 客户端与画板前端的所有图集生成路径都显式传入模式,不再依赖平台兜底。 -- [ ] 响应回显的 `sliceMode` 与请求声明一致;`grid` 时同时回显行列数。 -- [ ] 拒绝信息包含字段名、允许取值与决策分支;`sliceCount` 契约上限与切片上限一致。 -- [ ] 标准美术包声明 `sliceCount=4`,数量不符时在写入用途清单前失败关闭。 +- [x] 省略 / `null` / 空字符串 `sliceMode` 的图集生成请求在定价、入队、扣费和 provider 调用之前返回 `400`,错误体含 `field=sliceMode`。 +- [x] `grid` 缺 `gridX` 或 `gridY`、越界、乘积超限时 `400`;`connected-components` 携带 `gridX`/`gridY` 时 `400`。 +- [x] 公开契约、MCP / Agent 工具说明、Skill 与画板前端类型都要求显式声明,且不再声明任何默认值。 +- [x] AGC 客户端与画板前端的所有图集生成路径都显式传入模式,不再依赖平台兜底。 +- [x] 响应回显的 `sliceMode` 与请求声明一致;`grid` 时同时回显行列数。 +- [x] 拒绝信息包含字段名、允许取值与决策分支;`sliceCount` 契约上限与切片上限一致。 +- [x] 标准美术包声明 `sliceCount=4`,数量不符时在写入用途清单前失败关闭。 ## 证据要求 - 自动化:平台定向测试(缺失、空串、连通域带网格尺寸、grid 缺维度、正常两种模式)、OpenAPI 契约测试、前端与 AGC 客户端定向测试。 - 运行时:本地 `api-server` smoke 提交一次缺字段请求,确认返回 `400` 且无扣费 / 入队记录。 - 边界:确认失败发生在引用解析、定价、入队与 OSS 副作用之前;确认响应字段与请求一致。 + +## 本轮复核(2026-09-24) + +状态原为 `proposed` / `ready`(规范态),实现已经落地,本轮逐条核对并改记为 `implemented-awaiting-runtime-acceptance`: + +- 验收 1/2/6(缺失、空白、未知取值、模式与网格矛盾在副作用前 400 且带 `field=sliceMode`):`cargo test -p api-server slice_mode` → `slice_mode_must_be_declared_and_accepts_explicit_modes` 通过,断言 `400`、`field=sliceMode` 与「没有默认值 / grid / connected-components」的可执行文案;`cargo test -p api-server grid_dimensions_reject_more_than_maximum_output_slices` 通过。 +- 验收 3(公开契约、MCP / Agent 说明、Skill、画板前端都不再声明默认值):`docs/openapi/genarrative-external-v1.openapi.json` 的请求体 `required` 含 `sliceMode` 且响应回显同一字段;`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 tool_catalog_preserves_reviewed_resource_contracts` 通过(`sliceMode` 必填、无默认值、说明含决策要求);`.codex/skills/genarrative-external-editor-api` 与客户端技能包 `taonier-art-assets` 都写明「没有默认值」与两种模式的取舍。 +- 验收 4(自有调用方显式声明):`agent/direct_tool_bridge.rs` 在图集分支强制 `sliceMode` 并拒绝矛盾参数;`commands.rs` 与 `agent/direct_runtime/mod.rs` 按 kind 显式传入模式(标准美术包另带 `sliceCount=4`)。 +- 验收 7(标准美术包四张切片):`agent/direct_runtime/mod.rs` 对 `icon-spritesheet` 显式声明 `connected-components` + `sliceCount=4`,`tests/project.rs` 断言落盘含 `"sliceCount":4`,结果不是四张时失败关闭。 +- 前端:`npx vitest run src/services/image-editor/editorProjectClient.test.ts` → **62 passed**(含 grid 缺维度、connected-components 带网格尺寸两条拒绝路径)。 +- 仍未验证(需要真实环境):本地 `api-server` 缺字段请求的运行时 smoke(需要登录态与本地 SpacetimeDB)、真实平台图集生成返回四张切片的端到端结果。 + +## 逐条勾选依据(2026-09-24) + +- 条目 1/2/6:`editor_project_icon::tests::slice_mode_must_be_declared_and_accepts_explicit_modes`(省略/空白/未知取值均为 `400` + `field=sliceMode` + 允许取值与决策分支文案)、`grid_dimensions_reject_more_than_maximum_output_slices`;`EDITOR_ICON_SPRITESHEET_MAX_SLICES = 256` 与 OpenAPI `sliceCount.maximum = 256` 一致。失败发生在引用解析/定价/入队之前:切片声明在 `resolve_editor_icon_spritesheet_slice_request` 内解析,调用点早于价表与派发。 +- 条目 3:OpenAPI 请求体 `required` 含 `sliceMode` 且无默认值(`external_editor_api` 契约用例)、AGC `tool_catalog_preserves_reviewed_resource_contracts`(MCP 说明含决策要求且无默认)、`.codex/skills/genarrative-external-editor-api` 与客户端技能包文案。 +- 条目 4:`agent/direct_tool_bridge.rs` 强制图集分支声明模式并拒绝矛盾参数;`commands.rs` / `agent/direct_runtime/mod.rs` 按 kind 显式传值;画板前端 `editorProjectClient` 必填(`npx vitest run src/services/image-editor/editorProjectClient.test.ts` → 62 passed)。 +- 条目 5:响应字段由请求解析结果直接构造(`editor_project_icon.rs` 中 `"sliceMode": requested_slice_mode`,`gridX/gridY` 仅在 `grid` 时回填),因此回显与声明一致是构造不变量;**没有单独的运行时断言**,如需更强证据应补一条端到端用例。 +- 条目 7:`agent/direct_runtime/mod.rs` 对 `icon-spritesheet` 显式声明 `connected-components` + `sliceCount=4`,`tests/project.rs` 断言落盘含 `"sliceCount":4`,数量不符时失败关闭。 diff --git a/docs/project-memory/plans/【里程碑】多选素材批量标签-2026-09-17.md b/docs/project-memory/plans/【里程碑】多选素材批量标签-2026-09-17.md index 877c31dd9..6ffa7f52b 100644 --- a/docs/project-memory/plans/【里程碑】多选素材批量标签-2026-09-17.md +++ b/docs/project-memory/plans/【里程碑】多选素材批量标签-2026-09-17.md @@ -41,3 +41,10 @@ - 主线合并态 appSurface 450 项通过、20 项跳过;前端实现者完成批量接线后的同套回归,仍为 450 项通过、20 项跳过。 - 独立 review 的有效问题已落实:空白素材 ID 整批拒绝、超限错误定位到素材、批量锁操作名称、保存中输入锁、项目代次校验及首项为版本卡时入口原因可达。 - 浏览器工具当前无法连接,未将 jsdom 矩形/事件模拟称为真实客户端验收。没有推送、没有 CI 轮询、没有修改飞书。 + +## 本轮复验(2026-09-24) + +- 前端集成与模型:`npx vitest run tests/resourceBatchTagsIntegration.test.tsx tests/resourceBatchTagTargetModel.test.ts --root apps/ai-game-creator-shell` → **9 + 2 passed**(画布与资源面板两条入口、混合选择禁用、部分失败不留半写、切项目丢弃迟到回包、manifest 回读失败仍报「已保存但刷新失败」)。 +- 原生:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 batch_tag` → **12 passed**(追加保留原标签与分类、去重与上限、no-op 不写审计不推进 revision、审计失败回报已写入整批、缺目标不写、权限门面、未知字段拒绝、CAS 与项目身份)。 +- 顺带修掉一个测试可运行性缺陷:`resourceBatchTagsIntegration.test.tsx` 与 `resourceTagStatsRefresh.test.tsx` 用 `describe` / `it` 却没有导入(194 个 AGC 测试文件里只有这两个这样写),因此按仓库常见的 `--root apps/ai-game-creator-shell` 口径执行时会以 `ReferenceError: describe is not defined` 整文件失败;已按同目录套件惯例从 `./appSurface/harness` 显式导入,两种执行口径现在都能跑。 +- 仍未验收(需要真实客户端):在已登记素材上从画布多选工具栏与资源面板进入批量标签,确认新增标签、原标签保留、刷新后持久化与跨项目切换。 diff --git a/docs/project-memory/plans/【里程碑】对话回合唯一投影-2026-09-16.md b/docs/project-memory/plans/【里程碑】对话回合唯一投影-2026-09-16.md deleted file mode 100644 index c7e01f50a..000000000 --- a/docs/project-memory/plans/【里程碑】对话回合唯一投影-2026-09-16.md +++ /dev/null @@ -1,32 +0,0 @@ -# 对话回合唯一投影 - -- Version: 3 -- Status: superseded -- Date: 2026-09-16 -- Superseded by: `../【里程碑】DirectProject聊天真相源收敛-2026-09-16.md` -- Parent Spec: ../../technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md - -## 结论 - -本里程碑原先把「回合唯一投影」落在 Direct 回合事件 + `turn-stream.jsonl` + `tool-calls.jsonl` + 活动回合快照这条读路径上,方向已被推翻:聊天视图的输入只剩**项目对话历史**与**运行态事件**两项,Direct 回合事件、`turn-stream.jsonl`、`tool-calls.jsonl`、活动回合快照都不再是聊天视图的输入。后续实现与验收一律以 `../【里程碑】DirectProject聊天真相源收敛-2026-09-16.md` 与 `docs/adr/【ADR】DirectProject对话历史单一事实源-2026-09-16.md` 为准。 - -## 仍然有效的部分 - -1. 一个回合只有一个呈现入口,用户消息不丢失;历史里带不了身份(没有 id)的旧记录不得做位置猜配。 -2. 同一 item 的增量、完成、持久化与回读使用同一个身份、同一个顺序;重复快照不重复渲染。 -3. 工具调用的输入与输出都保留,展开后仍显示「输入 / 输出」。 -4. 已结束回合重进不显示提交中;真实运行回合可恢复。 -5. 用户消息时间只来自条目自己的时间戳,旧无时间记录不造值;完成后中间正文与工具统一折叠,最终回复与失败提示保持可见。 -6. 失败与中止说明只在运行期显示,不写进 `project.jsonl`;页面重进后不再出现。 - -## 已作废的部分 - -- 由活动回合快照接管运行中回合:改为由 `subscribe` bootstrap 事件判定(事件序列里 `turn.started` 之后没有 `turn.completed` 即运行中)。 -- 按 `turnId` 归并回合并把工具卡片挂在回合上:事件与条目都不再带回合身份,前端只有一个 `turnRunning` 布尔,卡片形状去掉 `turnId`。 -- 用 `turn-stream.jsonl` 的 `seq` 决定文本与工具的交替顺序:改为按运行态事件顺序 + 历史文件顺序投影。 -- 前端订阅 `game-creator-direct-turn-update`:改为 `subscribe` + `notify` 唤醒 `consume`(bootstrap 的事件直接 reduce,不再补一次 `consume`)。 - -## 当前证据 - -- 里程碑版本的静态检查结论(TypeScript、Cargo、编码、文档索引、`git diff --check`)仍然成立;该增量按当时授权未运行测试。 -- 新路径的证据要求见 `../【里程碑】DirectProject聊天真相源收敛-2026-09-16.md` 的「验收标准」与「证据要求」,其中包含解锁此前跳过的工具卡片渲染用例。 diff --git a/docs/project-memory/plans/【里程碑】对话总耗时与动态工具计时-2026-09-18.md b/docs/project-memory/plans/【里程碑】对话总耗时与动态工具计时-2026-09-18.md index d58672f77..3df247adf 100644 --- a/docs/project-memory/plans/【里程碑】对话总耗时与动态工具计时-2026-09-18.md +++ b/docs/project-memory/plans/【里程碑】对话总耗时与动态工具计时-2026-09-18.md @@ -35,3 +35,9 @@ - Edge 无头真实浏览器使用生产组件与 reducer、模拟生命周期事件:无新事件仍每 100ms 增长,单工具完成后冻结,另一工具与整轮继续增长,回合完成及重复完成事件不改变最终值。 - 无上游精确阶段时间时使用宿主观测毫秒,不宣称测得模型内部物理耗时;旧历史缺少完整生命周期时间时隐藏未知用时。 - 此证据不代表远程 CI 全绿。此前 PR 当前已推送提交的 run 2473 有两条 Rust shard 2 失败,仍需单独排查及后续 SHA 的远程结果。 + +## 本轮复验(2026-09-24) + +- 纯计时投影:`npx vitest run tests/elapsedDuration.test.ts tests/directTurnPresentation.test.ts --root apps/ai-game-creator-shell` → **16 + 17 passed**(未知/缺失/倒序边界的隐藏口径、整轮与工具组分别取时)。 +- 工具组与界面链路(含前组冻结、后组运行、并行、重试清空、迟到回合等):由 `npm run ai-game-creator-shell:check:web` 全量执行 → 185 files / 1808 passed / 14 skipped;仓库根 `npm test` → 416 files / 4391 passed / 26 skipped。 +- 仍未验证(需要真实客户端 + 真实 Provider):8 秒启动等待计入总耗时、100ms 递增与终态冻结在原生事件下的表现;本轮只有模拟原生事件与 jsdom 证据。 diff --git a/docs/project-memory/plans/【里程碑】平台会话身份与凭据分离-2026-09-16.md b/docs/project-memory/plans/【里程碑】平台会话身份与凭据分离-2026-09-16.md deleted file mode 100644 index 1a2b79806..000000000 --- a/docs/project-memory/plans/【里程碑】平台会话身份与凭据分离-2026-09-16.md +++ /dev/null @@ -1,54 +0,0 @@ -# 【里程碑】平台会话身份与凭据分离 - -| 字段 | 值 | -| ----------- | ------------------------------------------------------------------------------------------------------------- | -| Version | 1.0 | -| Status | implemented(待验收复核) | -| Date | 2026-09-16 | -| Parent Spec | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`(`2026-09-16 平台会话身份与凭据分离`) | - -## 目标 - -同一账号在长回合内发生 access token 续期时,在途的生成、编辑、上传、确认和下载 operation 必须继续可用;只有登录主体、服务 origin 或登出状态真正变化时才允许中止它们。刷新失败与并发刷新不得把仍然有效的会话判成未登录。 - -## 范围 - -- AGC renderer 的平台会话状态机:身份代次与 native 写入 revision 的分离,续期不再推进身份代次。 -- 原生 Rust `platform_session` 会话状态:身份判据、token 判据、写入顺序判据的分离。 -- 冻结平台会话的校验语义(外部编辑器 binding、生成 operation、MCP 工具会话)。 -- 独立 Runner 的平台会话安装 / 清除与 attach 参数。 -- AGC 与网站前端的刷新失败语义、并发刷新收敛重试。 -- `api-server` `/api/auth/refresh` 轮换失败时的响应语义。 - -## 不在范围内 - -- 不改 `refresh_session` 的持久化 schema,不引入服务端轮换宽限表。 -- 不改 `/api/external/v1` 路由、OpenAPI 或共享 DTO。 -- 不改生成、计费、账本幂等键与恢复语义本身。 -- 不改 Provider、MCP 工具白名单、审批或项目锁。 - -## 依赖与前置条件 - -- 现有 native revision 与 durable GUI owner claim 语义保持不变。 -- 现有 `authentication-required` 错误分类保持不变,只收窄其触发条件。 - -## 验收标准 - -- [x] 同一账号续期后,续期前建立的在途冻结会话校验通过;换号、退出和 origin 变化后校验失败关闭。 -- [x] 同一账号续期不推进 renderer 身份代次,也不使 `AuthenticatedClient` / Direct 配置判据把会话判成 stale。 -- [x] 迟到或更旧的凭据写入被 revision 拒绝,不能覆盖更新的 token,也不能复活已清除的会话。 -- [x] 瞬时刷新失败(网络错误、5xx、网关错误、响应契约异常)不清除本地会话与 access token。 -- [x] 刷新返回 401 时先用当前 cookie 收敛重试一次;重试成功继续使用新凭据,重试仍 401 才清会话。 -- [x] `/api/auth/refresh` 轮换失败不下发清空 refresh cookie 的响应。 - -## 证据要求 - -- 自动化:AGC Rust 定向用例(身份判据、revision CAS、冻结会话)、AGC 前端用例(代次与刷新失败语义)、`api-server` 定向用例(轮换失败响应)、网站 `apiClient` 用例(收敛重试)。 -- 运行时:AGC shell Rust 定向测试与前端测试;`api-server` 定向 `cargo test`。 -- 边界:换号 / 退出失败关闭、迟到写入拒绝、并发刷新竞争、token 不出现在错误文本与持久化中。 - -## 证据与未验证项 - -- 已获得:AGC `platform_session::tests` 12/12、`runner::tests` 平台会话相关 5/5、`assets::tests` 平台路由 2/2;AGC `appSurface` 前端套件 468 项全通过;网站 `src/services/apiClient.test.ts` 33/33;`cargo test -p api-server refresh_session` 3/3。 -- 未验证:依赖项目夹具的 AGC Rust 用例(`project::resource_editor::tests`、`project::external_editor_bindings::tests` 等)在本机全部以同一条环境错误失败——测试临时目录属主是 `BUILTIN\Administrators`,而进程用户是 `kdletters\kdletters`,严格 ACL 校验在夹具初始化阶段失败关闭,与本次改动无关;需要非提权或属主正确的运行环境才能补齐。 -- 未验证:真实 Provider 的并发生图 + 长回合保活端到端 smoke 未执行(需要有效平台登录态与付费生成)。 diff --git a/docs/project-memory/plans/【里程碑】抠图模式联调验收-2026-09-16.md b/docs/project-memory/plans/【里程碑】抠图模式联调验收-2026-09-16.md index e5f065108..8143916ac 100644 --- a/docs/project-memory/plans/【里程碑】抠图模式联调验收-2026-09-16.md +++ b/docs/project-memory/plans/【里程碑】抠图模式联调验收-2026-09-16.md @@ -1,7 +1,7 @@ # 抠图模式联调验收 Version: 1 -Status: 自动化与真实上游验收已执行;完整主站链路待本地数据库恢复 +Status: implemented-awaiting-runtime-acceptance(自动化与真实上游 BgFilter 验收已执行;完整主站登录/队列/资源回写链路待本地数据库恢复) Date: 2026-09-16 Parent Spec: ../../technical/【技术方案】AGC抠图模式与背景色透传-2026-09-16.md diff --git a/docs/project-memory/plans/【里程碑】文档素材Markdown预览-2026-09-16.md b/docs/project-memory/plans/【里程碑】文档素材Markdown预览-2026-09-16.md index 703167563..9c47cb4cc 100644 --- a/docs/project-memory/plans/【里程碑】文档素材Markdown预览-2026-09-16.md +++ b/docs/project-memory/plans/【里程碑】文档素材Markdown预览-2026-09-16.md @@ -1,7 +1,7 @@ # 文档素材 Markdown 预览 - Version: 1 -- Status: implemented-awaiting-validation +- Status: implemented-awaiting-runtime-acceptance - Date: 2026-09-16 - Parent Spec: `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的“文档与代码素材预览”。 @@ -21,3 +21,9 @@ ## 验收状态 已实现入口、弹窗、队列按需读取、Markdown 代码围栏与高亮;已通过 AGC TypeScript(含新增预览测试文件的静态类型检查)、编码、文档索引、CSS 语法和 diff 检查。回归用例未执行;原生客户端读取、弹窗焦点/滚动和视觉验收仍待验证,不进入下一里程碑。 + +## 回归用例执行(2026-09-24) + +- `npx vitest run tests/ResourceDocumentPreviewDialog.test.tsx tests/resourceDocumentPreviewModel.test.ts tests/ChatMarkdownMessage.test.tsx`:3 文件 / **30 passed**(弹窗加载、空、失败与身份切换;预览类型与扩展名派生;Markdown 标题/列表/表格、围栏、未知语言与大正文降级)。 +- 原状态 `implemented-awaiting-validation` 的原因是「按用户此前约束不运行测试」,该约束已不适用:回归用例现在已实际执行并通过。 +- 仍未验证(需要原生客户端):真实 Tauri 命令读取文档/代码正文、弹窗焦点与滚动行为、视觉验收。 diff --git a/docs/project-memory/plans/【里程碑】画布验收问题统一修复-2026-09-17.md b/docs/project-memory/plans/【里程碑】画布验收问题统一修复-2026-09-17.md index 52b061cbc..865db0d01 100644 --- a/docs/project-memory/plans/【里程碑】画布验收问题统一修复-2026-09-17.md +++ b/docs/project-memory/plans/【里程碑】画布验收问题统一修复-2026-09-17.md @@ -44,3 +44,9 @@ - 在途落点失败且整理无变化时可能留下一个空撤销步骤,失败提示仍可见,不导致正式素材数据丢失;低优后续事项。 - 已按确认创建 Issue #411、PR #412,并推送 `feat/agc-canvas-acceptance`;飞书未写回。用户另已授权合入 master、修复 CI 并持续推送到检查通过,不授权合并 PR 本身。 - 合入 master 后的 CI 2439 暴露五类检查偏差:图集 mock 缺少显式切分参数、工具目录断言未包含新增切分字段、更新插件迁移后的 HTTP 白名单期望过期、窗口空快照稳定化后的发布次数期望过期、测试文件末尾多空行。修复保持现行生产合同和权限范围,补齐参数/边界断言;两个 Rust 失败用例、原生合同门禁及窗口/落点四项前端用例已定向通过,仍需新提交的远程 CI 全量结果。 + +## 本轮复验(2026-09-24) + +- 画布与引用链路定向:`npx vitest run tests/resourceCanvasCardName.test.tsx tests/resourceCanvasBottomToolbar.test.tsx tests/resourceBookLayout.test.ts tests/resourceBookModel.test.ts tests/resourceReferenceInput.test.tsx tests/projectResourceLiveIntegration.test.tsx tests/projectResourceProjectionModel.test.ts tests/resourceCanvasAssetGenerationReferences.test.tsx --root apps/ai-game-creator-shell` → 8 文件 / **159 passed**。 +- 全量界面门禁(含工作台集成、多选移动、整理与撤销、任务占位与结算):`npm run ai-game-creator-shell:check:web` → 185 files / 1808 passed / 14 skipped;根 `npm test` → 416 files / 4391 passed / 26 skipped。 +- 仍未验证(需要真实客户端与真实 Provider):最后一版生成浮层的高度与横向居中在真实客户端复验、真实 Provider 生成 + Tauri IPC 全流程(涉及账号与费用,不默认触发)。 diff --git a/docs/project-memory/plans/【里程碑】策划Agent回合模型选择生效-2026-09-20.md b/docs/project-memory/plans/【里程碑】策划Agent回合模型选择生效-2026-09-20.md index 6b43a4417..f23430910 100644 --- a/docs/project-memory/plans/【里程碑】策划Agent回合模型选择生效-2026-09-20.md +++ b/docs/project-memory/plans/【里程碑】策划Agent回合模型选择生效-2026-09-20.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Version | 1.0 | -| Status | implemented(待验收) | +| Status | implemented-awaiting-runtime-acceptance | | Date | 2026-09-20 | | Parent Spec | [策划 Agent 生产迁移与工作区浏览方案 §4.1](../../technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md#41-策划对话模型与推理档选择) | @@ -26,19 +26,19 @@ ## 依赖与前置条件 -- [控件接入里程碑](./【里程碑】策划Agent模型与推理档控件接入-2026-09-20.md) 已验收。 +- 控件接入里程碑已验收并归档(结论见 [策划 Agent 生产迁移与工作区浏览 §4.1](../../technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md))。 - 主规范和本里程碑已评审,实施前编写仅覆盖本步的实现计划。 - 生效时机、主动重试与自动恢复的区分遵循主规范,不通过重建会话实现切换。 ## 验收标准 -- [ ] 新策划会话和旧策划会话下一次执行都使用当前已保存选择;旧模型不再永久覆盖新选择。 -- [ ] 发送、澄清、审批继续与主动重试的实际 Provider 请求使用新选择。 -- [ ] 执行中改配置不影响本次后续工具请求或瞬态自动重试,下一次用户执行才生效。 -- [ ] 自动恢复优先使用已有活动回合快照;旧记录缺推理档时按主规范补齐,不重复已执行工具副作用。 -- [ ] 切换后上下文、阶段、产物和审批身份保留,纯读取不改历史模型信息。 -- [ ] 配置/Provider 失败沿用可见错误,不静默降级、换模型或清空历史。 -- [ ] GameAgent 既有选择和运行行为通过兼容回归,没有借机修正其本征不足。 +- [x] 新策划会话和旧策划会话下一次执行都使用当前已保存选择;旧模型不再永久覆盖新选择。 +- [x] 发送、澄清、审批继续与主动重试的实际 Provider 请求使用新选择。 +- [x] 执行中改配置不影响本次后续工具请求或瞬态自动重试,下一次用户执行才生效。 +- [x] 自动恢复优先使用已有活动回合快照;旧记录缺推理档时按主规范补齐,不重复已执行工具副作用。 +- [x] 切换后上下文、阶段、产物和审批身份保留,纯读取不改历史模型信息。 +- [x] 配置/Provider 失败沿用可见错误,不静默降级、换模型或清空历史。 +- [x] GameAgent 既有选择和运行行为通过兼容回归,没有借机修正其本征不足。 ## 证据要求 @@ -46,3 +46,20 @@ - 运行时:在现有策划项目选择另一模型及推理档,触发下一次执行核对实际请求;真实供应商是否接受跨模型历史需按环境记录实测或未验证。 - 边界:验证恢复幂等和凭据不进入新增快照;无需新增通用权限或供应商测试体系。 - 全部验收后将主规范提案改为当前行为,更新稳定项目记忆并删除本次已完成临时计划。 + +## 延迟验证补执行(2026-09-24) + +原验证记录里「Rust 定向测试:已尝试编译,未执行测试用例」与「本地 HTTP fixture:已补充真实请求字段断言,尚未执行」两条,本轮已实际执行: + +- `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml design_runtime::tests -- --test-threads=1`:**24 passed / 0 failed**(含 `design_user_actions_apply_selection_and_tool_requests_keep_the_turn_snapshot`:本地 mock Provider 逐次捕获真实请求体,断言 `model` 与 `reasoning.effort` 跟随回合快照、运行中被改的全局配置不能改变在途回合;以及 `design_turn_selection_survives_config_changes_and_legacy_recovery`:旧记录缺 `modelSelection` 时保留会话模型、配置变化不反写已开始的回合)。 +- `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml design_session -- --test-threads=1`:**3 passed / 0 failed**。 +- 仍未运行:真实 Provider 与桌面端单回合 smoke(需要真实账号与费用)。 + +## 逐条勾选依据(2026-09-24) + +- 条目 1/4:`design_runtime::tests::design_turn_selection_survives_config_changes_and_legacy_recovery`(新旧会话取当前选择、旧记录缺 `modelSelection` 时保留会话模型并按配置补推理档、配置变化不反写已开始回合)。 +- 条目 2/3:`design_user_actions_apply_selection_and_tool_requests_keep_the_turn_snapshot`(本地 mock Provider 逐次捕获真实请求体,覆盖普通消息、工具请求、澄清回答、用户重试、审批批准与重复审批;运行中改配置后本轮后续请求仍是回合快照)。 +- 条目 6:`phase_checkpoint_failure_does_not_record_revision_or_start_model`、`design_first_submit_keeps_accepting_user_after_model_failure_and_replay`(失败沿用可见错误,不静默降级或清空历史)。 +- 条目 5:判据成立。① `agent::design_runtime::tests::design_user_actions_apply_selection_and_tool_requests_keep_the_turn_snapshot`(本轮复跑 24 passed 中的一条)在同一会话里连做四次切换:第一回合 A/高,执行中把配置改成 B/低,本回合两次请求仍是 A/高;下一回合按 B/低;澄清回答按 A/中;失败重试按 B/max;随后把阶段提交审批、配置改成 A/default 再批准,断言 `current_phase == "top_design"`、`session_id` 与提交前一致、历史仍保留原工具回执 `status-call`、会话 JSON 不含 API Key;同一条已处理的审批命令再执行一次不采样新配置、不重新请求 Provider,回合快照逐字段等于上一次。切换只影响后续执行,上下文/阶段/产物/审批身份原样保留。② `design_turn_selection_survives_config_changes_and_legacy_recovery`:旧记录缺 `modelSelection` 时保留会话模型,配置变化不反写已开始的回合。③ 前端 `tests/appSurface/design-agent.suite.ts` 的「persists Design Agent model and reasoning controls and reads them on reentry」:重进策划会话(纯读取)显示已保存的模型与推理档,且全程不出现 `continue_design_agent_session`,纯读取不产生新回合、不改历史模型信息。 +- 条目 7:判据成立,分「改动面」与「回归复跑」两部分。① 改动面:`81e0c41f1`(PR #436)只动了 `agent/design_runtime.rs`、`agent/runtime_protocol/design_session.rs`、`src-tauri/src/tests/mod.rs`、共用 composer(`ProjectSupervisorView.tsx`)、`styles.css`、appSurface 用例与文档,没有触碰 GameAgent 的 runtime driver、Provider 请求构造或做游戏提示词;composer 那处改动显式保留 GameAgent 原语义——`showModelControls = directCodex || designAgentActive`,`modelSelectRef` / `onReady` 只在有 DirectCodex 时挂上(源码注释即「策划只复用配置控件;GameAgent 保留原有提交校验」),没有借机改 GameAgent 的提交门禁或本征行为。 +- 条目 7(续):2026-09-24 复跑既有回归——`npx vitest run apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx` → **29 passed**(GameAgent / DirectCodex 模型选择控件既有行为);`npx vitest run apps/ai-game-creator-shell/tests/appSurface.test.ts` → **191 passed / 9 skipped**(含首页与项目工作台等 GameAgent 套件);`cargo test --offline model_selection -- --test-threads=1` → **2 passed**(`app_config_model_selection_only_updates_model_overlay`、`model_selection_default_flag_round_trips`);`cargo test --offline canonical_agent_reasoning_effort -- --test-threads=1` → **1 passed**(`canonical_agent_reasoning_effort_defaults_are_exhaustive_and_auditable`,各 Agent 推理档默认值)。边界:这是本地回归证据,不含真实 Provider 的 GameAgent 运行 smoke。 diff --git a/docs/project-memory/plans/【里程碑】策划Agent模型与推理档控件接入-2026-09-20.md b/docs/project-memory/plans/【里程碑】策划Agent模型与推理档控件接入-2026-09-20.md deleted file mode 100644 index 692ae4ba8..000000000 --- a/docs/project-memory/plans/【里程碑】策划Agent模型与推理档控件接入-2026-09-20.md +++ /dev/null @@ -1,53 +0,0 @@ -# 策划 Agent 模型与推理档控件接入 - -| 字段 | 值 | -| --- | --- | -| Version | 1.0 | -| Status | accepted(用户已授权提交、进入第二步) | -| Date | 2026-09-20 | -| Parent Spec | [策划 Agent 生产迁移与工作区浏览方案 §4.1](../../technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md#41-策划对话模型与推理档选择) | - -## 目标 - -策划对话复用已有模型和推理档控件,能够读取和保存全局选择,保持 GameAgent 兼容性。 - -## 范围 - -- 输入区域中控件的显隐、位置、策划面板布局与必要的宿主接线。 -- 复用原有目录、默认模型、保存和错误提示,不复制逻辑。 -- 策划发送、澄清、审批继续和主动重试保持原流程;不新增模型可用性检查或提交门禁。 -- 重新进入策划时显示保存值;执行中可以调整后续选择,但原输入与提交忙态维持不变。 - -## 不在范围内 - -- 不修改策划 Provider 的模型选择和推理档采样逻辑,不声称旧会话已能切模型。 -- 不检查、修复或重构 GameAgent 组件本征不足,不引入通用缓存、同步、保存、下拉或配置框架改造。 -- 不为策划引入队列、语音或素材引用,不更改默认推理档。 - -## 依赖与前置条件 - -- 主规范本节与本里程碑完成评审。 -- 实施前仅为本里程碑编写实现计划,确认现有 GameAgent 对应回归用例与策划宿主入口。 -- 本步作为内部接入结果;第二步完成前不单独发布为完整可切模型功能。 - -## 验收标准 - -- [ ] 策划入口显示原模型及推理档控件,没有重复实现或第二份设置。 -- [ ] 选择走原保存通道;重新进入显示已保存值;保存失败显示原有错误反馈。 -- [ ] 策划提交和报错流程保持原样,没有新增模型检查;原控件内部行为不改造。 -- [ ] 策划忙态、待审批/澄清行为保持;新增布局在宽/窄面板可操作。 -- [ ] GameAgent 原控件的显示、选择、发送校验、忙态和运行行为通过相关回归。 -- [ ] 交付明确记录旧策划会话仍沿用旧模型,留待下一里程碑解决。 - -## 证据要求 - -- 自动化:现有界面测试中增加策划入口的集成场景,复用 GameAgent 回归;运行 AGC 类型检查、文档索引、编码和 diff 检查。 -- 运行时:桌面与窄面板选择、保存、重新进入和一次策划发送 smoke;缺失环境如实标注。 -- 边界:只验证接入所需的失败和忙态,不扩展为现有组件全量审计。 -- 通过本步验收后,才准备并执行模型生效里程碑的实现计划。 - -## 当前交付 - -已接入原控件及策划布局,按用户最终要求保留策划提交、审批、澄清、重试与报错流程,没有新增模型检查。原控件与 GameAgent 的提交逻辑未修改;旧策划会话固定模型的限制仍由第二步解决。 - -新增三条控件集成用例(保存重进、运行中选择、保存失败反馈)。用户已授权提交第一步、进入第二步。 diff --git a/docs/project-memory/plans/【里程碑】资源画布支持引擎资源预览-2026-09-17.md b/docs/project-memory/plans/【里程碑】资源画布支持引擎资源预览-2026-09-17.md index 2e0942947..f963b4f67 100644 --- a/docs/project-memory/plans/【里程碑】资源画布支持引擎资源预览-2026-09-17.md +++ b/docs/project-memory/plans/【里程碑】资源画布支持引擎资源预览-2026-09-17.md @@ -3,7 +3,7 @@ | 字段 | 值 | | ----------- | ---------------------------------------------------------------------- | | Version | 1.0 | -| Status | implemented; 真机 Cocos 工程验收待补 | +| Status | implemented-awaiting-runtime-acceptance(真机 Cocos 工程验收待补) | | Date | 2026-09-17 | | Parent Spec | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` | @@ -55,3 +55,9 @@ - 运行时(卡面几何):同一现场量 `cube.glb` 卡的卡片盒 / 卡面 / 类型角标 / 缩略图四个矩形的 `x/y/w/h`,在**指针移开、悬停、选中**三种状态下**完全一致**(此前悬停会把卡面四边各吃 1px);缩略图渲染尺寸为 `356x252`(布局盒 178×126 × 2 超采样),绘制比 1.4127 与卡面盒 267×189 的比例一致,缩放后不发虚、不裁切。证据:`agc-fix-hover.png` / `agc-fix-selected.png`。 - 边界:`.meta` 仍然只可发现、不可登记;引擎工程的 `library/` / `temp/` / `profiles/` / `local/` 不进发现结果,同名目录在非引擎工程里照常列出;`.pcm` / `.texture` 等容器不发起读取。 - 未验证:真机客户端内的视觉验收(本机没有可用的 Cocos 工程实例)。Rust 侧其余仍用 `tempfile::tempdir()` 的既有用例在本机仍被 `Windows 安全对象不属于当前用户` 阻断(本次把预览与导入这两个模块的用例改用工程自带的 `crate::tests::canonical_test_tempdir`,它们已能真实跑通)。 + +## 本轮复验(2026-09-24) + +- 原生发现/登记/预览通道:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- cocos resource_inspect agent_asset_import --test-threads=1` → **28 passed / 1 ignored**(引擎工程发现分类、登记、结构摘要与二进制降级、TGA→PNG 转码、模型媒体类型签名)。 +- 前端卡面契约:`npx vitest run tests/resourceCocosPreviewContract.test.tsx --root apps/ai-game-creator-shell` → **10 passed**;资源链路批跑(卡面命名、底部工具栏、画本布局/模型、引用输入、实时集成、投影模型、生成引用)→ 8 文件 / **159 passed**。 +- 仍未验证:真实用户 Cocos 工程的滚动浏览视觉验收(2026-09-17 的证据来自本机临时夹具工程,非用户工程);`#[cfg(unix)]` 的资源打开竞态用例在 Windows 主机不执行。 diff --git a/docs/project-memory/plans/【里程碑】退役AGC项目对话斜杠命令与终端swarm chat入口-2026-09-22.md b/docs/project-memory/plans/【里程碑】退役AGC项目对话斜杠命令与终端swarm chat入口-2026-09-22.md deleted file mode 100644 index 581077bf8..000000000 --- a/docs/project-memory/plans/【里程碑】退役AGC项目对话斜杠命令与终端swarm chat入口-2026-09-22.md +++ /dev/null @@ -1,85 +0,0 @@ -# 【里程碑】退役AGC项目对话斜杠命令与终端swarm chat入口-2026-09-22 - -状态:已完成 -父规范:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` - -## 目标与判据 - -一句话目标:AGC 应用内不再存在任何斜杠命令语义,终端 swarm chat CLI 入口(`--swarm-chat`)连同其命令层整体退役,且不再残留只服务这两者的实现、测试、文案与构建期门禁;行为上等同于它们从未存在。 - -验收判据: -- AGC 应用内(`apps/ai-game-creator-shell/src/**`)除路径/路由字面量外,不存在形如 `'/xxx'` 的命令字面量,也不存在对 `/` 开头输入的命令分支。 -- 斜杠命令专属模块与其导出全部消失,`projectSummary` 桶文件只保留现役导出。 -- 权威文档不再承诺「聊天输入 `/`」能力,终端章节点也不再把控制命令列为入口。 -- 终端侧不再存在 swarm chat 入口与其命令层;`--agent-run`、`--agent-enqueue`、`--agent-steer`、`--agent-resume`、`--agent-context-compact`、`--preview-serve` 等运维类控制命令保持现役。 -- 依赖终端入口的真实 E2E 与脚本(`user-input`、`supervisor-autonomous-playable-lane-defense`、三个 supervisor-swarm 混合套件、`agc:test`、`agc:test:chat*`、`agc:chat`、`agc:swarm`)与交互式 CLI harness 管道一并消失。 -- 不新增任何守卫测试或 check 脚本条目。 - -## 范围 - -范围内(删除): -- `features/project-summary/projectSummaryConstants.ts` 的 `chatCommandHelp` 与全部命令清单常量。 -- `features/project-summary/chatCommandMetadata.ts`(斜杠命令参数校验文案)。 -- Direct 聊天的 `/history` 精确匹配分支与 `reloadHistory`。 -- `chatPromptPolish` 的 `/` 前缀绕过分支。 -- `memoryCommands.ts` 的 `parseRememberInput`(`/remember` 参数解析器)。 -- 只服务退役 Supervisor 摘要面板、零外部调用的 `project-summary/*Summaries.ts` 与 `agentTrace.ts`。 -- `/sync-canvas-project`、`/read `、`/trace` 的草稿回填死链(前端 `agentPresentation.ts` + Rust `suggested_canvas_tool_call`)。 -- 无人调用的 Tauri 命令 `get_game_creation_agent_capabilities`、`get_limited_local_commands`。 -- 钉住上述字符串的构建期门禁条目与专属测试。 -- 终端 swarm chat 入口与整个命令层:`cli.rs` 的 `SwarmChat` 变体、`--swarm-chat` 解析与派发、`src/swarm_cli.rs` 与 `src/swarm_cli/` 整个目录(输入解析与帮助输出、`/agents`、`/status` 打印器、`/goal` 引擎、`/compact`、`/resume`、`/quit` 退出分支、观察器、报告、turn 派发与等待)、`SwarmChatFlow`、`SwarmTurnObservation`、`SwarmTurnOutcome::Quit`、`SwarmConfirmationResolution::Quit`、`SWARM_TURN_*_ERROR`,以及 `swarm_cli/input.rs` 中那份只为终端命令存在的 `agent.compact` / `agent.resume` / `agent.run_status` 权限校验(同名权限 id 在现役 Tauri 命令与 Runtime 生命周期上的门禁保持不动)。 -- 只服务终端交互内核的 `agent/interaction.rs` 整层:`AgentInteractionAction`、tool registry、`game_creator_agent_uses_interaction_kernel`、`decide_game_creator_agent_interaction_turn_for_session_at`、`AgentInteractionProviderStreamSink`;其上的自然语言 steer 决策 LLM 路径 `decide_game_creator_agent_runtime_steer_at` 在收尾复查后一并删除,见「收尾清理」。 -- 只能由命令触达的打印器:`print_runtime_response_stream_status` 及其专属测试。 -- 依赖终端入口的脚本与套件:`scripts/agent-swarm-test-chat.mjs`、`scripts/agent-runtime-deterministic-playable-e2e.mjs`、`scripts/deterministic-lane-defense-provider.mjs`,套件 `user-input`、`supervisor-autonomous-playable-lane-defense`、`supervisor-swarm-autonomous-chat`、`supervisor-swarm-static-isolated-autonomous-chat`、`supervisor-swarm-collaboration-policy-mixed-recovery`,以及 harness 里的交互式 CLI 管道(`startInteractiveCli`、`writeInteractiveCliLine`、`waitForInteractiveCli*`、`closeInteractiveCli`、`activeInteractiveCliSessions`、`answerRemainingInteractiveQuestions` 等)与只服务这些套件的混合套件分支、状态字段、sentinel 与 npm 脚本。 同时清掉只被这些套件调用的 harness 残件:`collaboration-assertions.mjs` 的混合/静态隔离断言族(`supervisorSwarmMixed*`、`observeSupervisorSwarmStaticIsolatedProviderOverlap`)、`repair-recovery.mjs` 的静态隔离观测调用点、evidence 模板与校验里的 `mixed*` / `staticIsolated*` / `initialBatchRecovery*` 占位字段,以及 `self-test.mjs` 中对应的合成用例与汇总字段。 - -范围外(保留): -- 命令 id 注册表 `GAME_CREATION_APP_COMMANDS` 与 `GameCreationAppPermission`(项目权限策略词汇表;App 前端只用 `GameCreationAppCommandDescriptor` 类型表达权限判定与审计粒度,数组本体由 Rust 策略路径消费)。 -- `needsInitializedChatProject` 与项目权限策略链路。 -- Rust 侧路径/路由的 `/` 前缀校验。 -- `--agent-run`、`--agent-enqueue`、`--agent-task`、`--agent-steer`、`--agent-retry`、`--agent-cancel`、`--agent-confirm`、`--agent-resume`、`--agent-runtime-status`、`--agent-goal-*`、`--agent-context-compact`、`--runner-status`、`--runner-shutdown-if-idle`、`--llm-status`、`--preview-serve`、`--environment-check`、`--direct-codex-chat` 等运维与开发 CLI 控制命令。 -- 保留的真实 E2E 套件:`supervisor-swarm`、`supervisor-swarm-transient-retry`、`supervisor-swarm-final-reply-transient-retry`、`supervisor-swarm-tool-plan-handoff-runner-kill`、`goal-runtime`、`response-stream`、`web-search`、`context-compaction`、`scoped-agents`、`project-skill`、`parallel-read`、`steer-runner-kill`、`process-session`。 - -## 检查点 - -1. 斜杠语义层:Direct `/history`、润色绕过、`chatCommandHelp`/`chatCommandMetadata`、`parseRememberInput`、桶文件与门禁、专属测试。 -2. 死链与死模块:草稿回填链(前端 + Rust + 断言)、零调用摘要模块、`agentTrace.ts`。 -3. 无人调用的能力清单 Tauri 命令。 -4. 文档收口:AGC 主专题命令承诺、ADR、`decision-log.md`、`CONTEXT.md`。 -5. 终端 swarm chat 命令层与只服务它的权限门禁、打印器、专属测试。 -6. 终端 swarm chat 入口本体、交互内核、`--swarm-chat` 派发与其专属 Rust 测试。 -7. 依赖终端入口的 e2e 套件、deterministic wrapper/provider、npm 脚本、构建期门禁条目、harness 交互式 CLI 管道、混合套件分支,以及随之失效的混合/静态隔离断言族与 evidence 占位字段。 -8. 文档收口:终端入口退役后主实施计划、Runtime 文档、ADR、decision-log、pitfalls、里程碑计划的最终口径。 - -## 验证 - -- `npm run --workspace apps/ai-game-creator-shell typecheck`(含 `skill-pack:check` 与 `check-config.mjs`):通过。 -- 定向用例 `npx vitest run tests/appSurface.test.ts`:211 tests(202 passed / 9 skipped);`chatPromptPolish`、`rememberCommand`、`ChatMarkdownMessage`、`agentRuntimeModel` 等相关用例集通过。 -- `cargo check --tests`:0 error;删改文件无新增 `dead_code` 告警(按「父提交 vs 本次」引用数逐条比对告警标识符确认)。 -- `npm run check:encoding`、`npm run check:doc-index`、`git diff --check`:通过。 -- 真实 E2E harness 自检 `node scripts/agent-runtime-real-e2e.mjs --self-test`:`status: PASS`;harness 相对与具名 import 全部可解析。 -- 收尾清理(2026-09-23,LLM steer 判定链):`cargo check --tests` 0 error,告警与改动前基线一致(无新增 `dead_code`);`npm --workspace apps/ai-game-creator-shell run typecheck`、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` 通过;幂等复核 `steer_decision` / `interrupt_for_steer_decision` / `decide_game_creator_agent_runtime_steer_at` 在 `apps/`、`packages/` 源码中零命中。 - -## 文档收口 - -- `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`:删除全部「聊天输入 `/`」能力条目,保留并改写其中的非命令事实;`/compact`、`/mcp`、`/goal`、`/resume` 的终端承诺改为对应 `--agent-*` 入口。 -- `docs/technical/【技术方案】AI游戏创作Agent Runtime V1.1-2026-07-12.md`:删除终端 swarm chat 入口整节,控制面统一记为 `--agent-*` CLI(`/goal` → `--agent-goal-*`、`/compact` → `--agent-context-compact`、`/mcp` → 开发配置面板与真实 E2E 核验);终端不再承担任何交互式聊天职责。 -- `docs/adr/【ADR】退役AGC项目对话斜杠命令与终端swarm chat入口-2026-09-22.md`:本次决策与影响边界。 -- `docs/project-memory/shared-memory/decision-log.md`:新增 2026-09-22 决策条目,并清理已被本次退役取代的历史命令条目。 -- `docs/project-memory/shared-memory/pitfalls.md`、`docs/project-memory/plans/【里程碑】DirectProject聊天真相源收敛-2026-09-16.md`:移除 `/history` 入口表述,改为「显式重新加载对话」。 -- `CONTEXT.md`:新增「项目对话输入」「项目命令 id」术语,把「斜杠命令」标为已退役说法;不再出现 `/history` 重读入口。 -- `docs/README.md`:登记新 ADR。 - -## 收尾清理 - -复查(2026-09-23)发现退役残留与随之产生的零引用代码,按同一口径清理: - -- 配置向导 `scripts/game-creator-config-wizard.mjs`:删除指向已删脚本的 `npm run test:chat` 调用、失去含义的 `--configure-only` 开关,以及只服务该分支的 `askYesNo` 与 `npmCommand`。 -- 用户文案:App 内 `请先用 /project 设置本地项目。` 改为 `请先打开本地项目。`。 -- 注释与 prompt:`chatPromptPolish` 头部注释的 `/` 命令表述、`harness/process.mjs` 与 `scripts/check-config.mjs` 中指向已退役入口的说明,以及 `interaction.json` 中只服务已删交互内核的 7 个键(`execute_description`、`resume_description`、`project_location_description`、`protocol`、`system`、`user`、`user_with_context`)。 -- harness 死导出:`runtime-state.mjs` 的 4 个 schema 常量、`assertions/runtime.mjs`、`harness/project.mjs`、`collaboration-policy.mjs`、`persistence.mjs` 中因调用方被删而零引用的函数,连同因此失去用途的 import。 -- 无前端调用方的 Tauri 命令 `start_game_creator_agent_runtime_task` 与 `steer_game_creator_agent_runtime_task` 全部删除(`main.rs` 注册与 `check-config.mjs` 条目同步移除)。删掉 steer 命令后其唯一非测试入口的整条 LLM steer 判定链一并退役:`agent/interaction.rs`(`runtime_steer_decision` 工具、判定请求构建、响应解析、`decide_game_creator_agent_runtime_steer_at`)、`runtime.interrupt_for_steer_decision` RPC 与派发分支、持久 decision 记录(`agent.runtime.steer_decision`)、`AgentRuntimeProviderInterrupt::applied_steer_cursor`、`AgentRuntimeSteerResult` 的 `assistantReply / interruptDecision / decisionReason` 字段、`steer_decision_*` prompt 键,以及只测该链条的 provider / runner / runtime_state 用例。 - -## 未做与边界 - -- 不为退役概念新增守卫测试或断言残留字符串的 check 条目。 -- 不为终端入口与已删套件补充替代实现、兼容别名或迁移提示。 diff --git a/docs/project-memory/plans/【里程碑】退役策划Agent V1V2解耦清理-2026-09-15.md b/docs/project-memory/plans/【里程碑】退役策划Agent V1V2解耦清理-2026-09-15.md index ccc9a2dd9..a875a9cb4 100644 --- a/docs/project-memory/plans/【里程碑】退役策划Agent V1V2解耦清理-2026-09-15.md +++ b/docs/project-memory/plans/【里程碑】退役策划Agent V1V2解耦清理-2026-09-15.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Version | 1.0 | -| Status | proposed | +| Status | implemented-awaiting-runtime-acceptance | | Date | 2026-09-15 | | Parent Spec | `docs/technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md` | @@ -35,15 +35,36 @@ ## 验收标准 -- [ ] “做方案”入口和已有 Design Agent 项目只调用当前 Design Agent IPC,不再调用旧 `planning_*_v2` IPC。 -- [ ] 当前 Design Agent 的消息、reasoning、澄清、阶段审批和重试行为不依赖旧 V2 状态变量。 -- [ ] 源码中不再存在旧 V2 TypeScript 会话适配层、旧 `PlanGdd` 类型和旧前端审批契约。 -- [ ] 旧前端测试、事件测试和样式残留被删除或改为当前 Design Agent 契约。 -- [ ] 不主动修改做游戏 Supervisor + 16 Agent DAG;因共享退役代码删除产生的编译错误得到最小修复。 -- [ ] 前端 typecheck、相关定向测试、编码检查和 diff 检查通过;触及 Rust 时对应 cargo check 通过。 +- [x] “做方案”入口和已有 Design Agent 项目只调用当前 Design Agent IPC,不再调用旧 `planning_*_v2` IPC。 +- [x] 当前 Design Agent 的消息、reasoning、澄清、阶段审批和重试行为不依赖旧 V2 状态变量。 +- [x] 源码中不再存在旧 V2 TypeScript 会话适配层、旧 `PlanGdd` 类型和旧前端审批契约。 +- [x] 旧前端测试、事件测试和样式残留被删除或改为当前 Design Agent 契约。 +- [x] 不主动修改做游戏 Supervisor + 16 Agent DAG;因共享退役代码删除产生的编译错误得到最小修复。 +- [x] 前端 typecheck、相关定向测试、编码检查和 diff 检查通过;触及 Rust 时对应 cargo check 通过。 ## 证据要求 - 自动化:`npm --prefix apps/ai-game-creator-shell run typecheck`、相关 appSurface 定向测试、`npm run check:encoding`、`git diff --check`。 - 运行时:至少验证“做方案”新项目进入 Design Agent、已有 Design Agent 会话恢复、澄清/审批回合可继续。 - 边界:确认 DirectCodex 和做游戏既有入口未被旧策划清理改动;确认旧 V2 IPC 字符串和旧事件契约不再进入现役前端。 + +## 源码级验收(2026-09-24) + +- `planningSessionV2.ts` 已不存在;`src` 内检索 `planning_[a-z0-9_]*_v2` / `planningV1` / `planningV2` 无命中,做方案入口只调用 `design_agent_session` / `continue_design_agent_session` / `hydrate_design_agent_session` 等当前 Design Agent IPC。 +- 旧 Plan GDD 类型与旧策划流工厂已清空:本轮删掉测试 harness 里无调用方、且引用了已不存在类型的 `createPlanGddStateView` 与 `planningResponseStream`(两者原本还导出给 suite);`PlanGdd` / `planning-session-v2-stream` 在 `src` 与 `tests` 已无命中。 +- 旧策划样式无残留:`plan-gdd` / `planning-lane` / `gdd-approval` 在 `src` 样式与组件内无命中。 +- Rust 侧同批退役见 decision-log 2026-09-21 条目:`planning_gdd_model.rs`、`planning_policy_v2.rs`、`planning_session_v2.rs`、`planning_*_v2` 命令与前端契约全部删除,不保留兼容别名或双跑路径。 +- 自动化:`npx vitest run tests/appSurface.test.ts tests/gamePublishFeedback.test.tsx` 195 passed / 9 skipped;`npm run ai-game-creator-shell:check:web` 185 files passed / 1 skipped、1806 tests passed;`npm run check:doc-index`、`npm run check:encoding`、`git diff --check` 通过。 +- 仍未取得:真实“做方案”新项目进入 Design Agent、已有会话恢复、澄清与阶段审批回合在真机 + 真实 Provider 下的连续验收。 + +因此状态从 `proposed` / `ready` 改为 `implemented-awaiting-runtime-acceptance`:源码级判据全部成立,缺真机运行时证据。 + +## 逐条勾选依据(2026-09-24) + +- 条目 1/2/3:`rg "planning_[a-z0-9_]*_v2|planningV1|planningV2" apps/ai-game-creator-shell/src` → 0 命中;`planningSessionV2.ts` 不存在;做方案入口只调用 `design_agent_session` / `continue_design_agent_session` / `hydrate_design_agent_session`。 +- 条目 4:本轮删掉测试 harness 里无调用方、且引用已删除类型的 `createPlanGddStateView` / `planningResponseStream`;`PlanGdd`、`planning-session-v2-stream`、`plan-gdd` 样式在 `src` 与 `tests` 内均无命中。 +- 条目 6:`npx vitest run tests/appSurface.test.ts tests/gamePublishFeedback.test.tsx` 195 passed;`npm run ai-game-creator-shell:check:web` 185 files / 1808 passed;`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` 通过。 +- 条目 5:按「退役提交的文件清单 + 当前状态」两条线取证,判据成立。① 退役提交的删除面集中在 planning 专属对象:`876529e66` 删除 Project Supervisor 前端链路并把项目对话收敛到 DirectProject 与立项策划(改动落在 `src/App.tsx`、`src/features/**`、`src-tauri/capabilities/*`、`windows.rs`),`70271b408`(PR #355)删除 `planning_gdd_model.rs` / `planning_policy_v2.rs` / `planning_session_v2.rs` 三个 Rust 模块、对应命令、前端 `planningSessionV2.ts`、`GddApprovalCard.tsx` 与其测试和样式。 +- 条目 5(续):同一提交对做游戏 DAG 共享代码只有最小修复——`agent/runtime_protocol.rs` 去掉三处 `mod` / `pub use`;`agent/runtime_driver/main_loop.rs` 删掉引用 `PlanningStorageError` 的未用 helper;`project/write_lock.rs` 与 `delegation.rs` 只改文档注释(去掉已删模块名);`agent/runtime_tools/delegation.rs` 只删 planning 专属的 `PlanClarification` / `UserRevision` 两种跳转旁注及其测试,做游戏链路那支 `Repair` 旁注保留原文;`delegation.rs` 另有一处测试 fixture 文本从 `game/fast_gdd.md` 改为 `design.md`。 +- 条目 5(续):做游戏链路的授权信号仍在——`apps/ai-game-creator-shell/src-tauri/prompts/runtime/texts/runtime.json` 的 `delegation_repair`(「这是对已认领委派 … 的唯一返工轮。」)逐字未改,`agent/runtime_tools/delegation.rs` 的注释继续说明它是 `design-foundation` / `art-director` / `art-asset-plan` 的 `replaceExisting` 唯一许可。 +- 条目 5(续):当前状态直接跑做游戏 DAG 合同——`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline autonomous_game_build -- --test-threads=1` → lib 目标 **28 passed / 0 failed**(2909 filtered out),含 `new_autonomous_root_contract_resets_all_sixteen_seed_tasks`、`standard_profile_keeps_confirmation_policy_unchanged`、`autonomous_game_build_recovery_aborts_legacy_confirmation_batch_and_replans`。也就是说退役后做游戏 Supervisor 与 16 Agent DAG 既没有被改成别的行为,也没有留下编译或测试失败。 diff --git a/docs/project-memory/plans/【里程碑】退役策划V2 Rust Runtime清理-2026-09-14.md b/docs/project-memory/plans/【里程碑】退役策划V2 Rust Runtime清理-2026-09-14.md deleted file mode 100644 index 8fcab81ad..000000000 --- a/docs/project-memory/plans/【里程碑】退役策划V2 Rust Runtime清理-2026-09-14.md +++ /dev/null @@ -1,38 +0,0 @@ -# Version - -V2-RUST-RETIRE-1 - -# Status - -in-progress - -# Date - -2026-09-14 - -# Parent Spec - -`docs/technical/【技术方案】策划会话RuntimeV2接入与旧链路退役-2026-09-03.md` - -# 目标 - -删除已经被独立 Design Agent 取代的旧策划 V2 Rust Runtime、Tauri 命令注册和仅服务 V2 的模块导出,使桌面壳继续编译并保留做游戏 Agent 与新版 Design Agent。 - -# 边界 - -- 删除 `planning_policy_v2`、`planning_session_v2` 及仅供这两者使用的 V2 注册和调用。 -- 删除 V2 专属的 Tauri command 注册、模块导出和测试入口。 -- 保留 `design_runtime`、`design_tools`、`design_session`、通用 runtime、DirectProject 和做游戏 Agent。 -- 本里程碑不处理前端 V2 数据层、UI、文档索引和共享运行时中的可选清理。 - -# 验收标准 - -1. Rust 源码不再编译 `planning_policy_v2.rs` 或 `planning_session_v2.rs`。 -2. `main.rs`、`commands.rs` 和 runtime protocol 不再注册或导出 V2 命令。 -3. 新版 Design Agent 与做游戏 Agent 的 Rust 编译路径保持可用。 -4. 相关定向 Rust 测试和 `cargo check` 通过。 - -# 依赖 - -- 当前分支已包含 PR159 的 V1 清理。 -- 前端 V2 调用暂时保留,待后续里程碑同步删除。 diff --git a/docs/project-memory/plans/【里程碑】项目客户端占用锁收敛-2026-09-14.md b/docs/project-memory/plans/【里程碑】项目客户端占用锁收敛-2026-09-14.md index 218b10182..97824f478 100644 --- a/docs/project-memory/plans/【里程碑】项目客户端占用锁收敛-2026-09-14.md +++ b/docs/project-memory/plans/【里程碑】项目客户端占用锁收敛-2026-09-14.md @@ -28,3 +28,30 @@ Parent Spec: `docs/technical/【技术方案】AI游戏创作智能体App实施 - Runner 的 `execution-owner.lock` 如何迁移到统一客户端占用锁,需要补充跨进程启动、恢复和诊断测试后再落地。 - 同进程**跨线程**重入(持锁调用链在 `await` / `spawn_blocking` 之后于其它线程再次取锁)仍会走有界等待,预算耗尽时报“项目正在被其他写操作占用”。发现这类现场时按 2026-08-27 的既有处置改用 `*_locked` 入口复用已有 guard(`project-memory/shared-memory/pitfalls.md`「持锁调用链二次取锁」),不放宽整条锁的串行化语义。 + +## 锁现状盘点与卡点(2026-09-24) + +验收标准 1/2/3/5 本轮已实测成立,第 4 条(客户端占用入口与 Runtime 写入入口不各自维护第二个项目级锁文件)卡在一个必须由产品/架构决定的问题上,不能在实现里单方面选。 + +### 现存的项目级锁文件(全量枚举) + +- `.agent/project.lock`(`src/main.rs` 的 `PROJECT_WRITE_LOCK_PATH`,`project/write_lock.rs`):GUI 侧每个写命令的短时写锁;同线程重入复用、其它线程/进程有界等待与终态占用、死进程残留回收都在这一把上。 +- `.agent/runtime/execution-owner.lock`(`runner/protocol.rs` 的 `EXTERNAL_AGENT_RUNNER_PROJECT_OWNER_PATH`):Runner 进程的跨进程 execution owner,配 `.agent/runtime/execution-owner.json` 诊断投影。 +- `.agent/workbench/resource-layouts/.layout.lock`、项目历史的 `append.lock`:子资源与追加写的底层一致性机制,不属于本里程碑说的「项目级占用」。 + +### 为什么第 4 条不能直接落地 + +- Runner 的 owner 是**长时锁**:`runner/state.rs` 的 `project_execution_owners` 在首次 `claim_project_execution_owner` 后保留到进程结束(claim 只在 dispatch 的写请求入口发生,没有释放路径),而 `.agent/project.lock` 是**逐操作短时锁**,GUI 侧 30+ 个写命令(`commands.rs` 里成片的 `acquire_project_write_lock`)都依赖它。 +- 因此「Runner 长时持有 `.agent/project.lock`」等于在 Runner 存活期间让所有 GUI 写命令变成「项目正在被其他写操作占用」——这是语义回退,不是收敛。两条可行路线都会改变现有产品行为,必须选一条: + - 路线 A(Runner 成为项目唯一写者):GUI 的写命令改为经 Runner 转发。CLI 侧已经是这个口径(`require_external_agent_runner_for_cli_runtime_write`),但 GUI 侧改动面很大,需要单独立项与灰度。 + - 路线 B(改执行占用的判据):用占用记录 + 持有者 liveness 取代 OS 锁。这与 shared-memory 决策记录 2026-07-12 的安全合同直接冲突——「execution-owner 的 OS 锁文件与 JSON 诊断投影分离……诊断内容不得作为接管依据」,接管必须依靠稳定目录句柄上的系统锁,不能降级成读 JSON 判 owner。 +- 结论:第 4 条不是实现细节,是要先定「谁写项目」或「是否修改执行占用的安全合同」。在决定之前,本里程碑保持 `in-progress`,执行占用的恢复诊断合同不变(主规范 2026-09-14 小节已写明「完成前不改变其恢复诊断合同」)。 + +### 本轮实测(验收标准 1/2/3/5) + +- 同一线程重入复用、释放后可再次取得:`project_write_lock_reuses_same_process_owner_and_releases_on_drop`。 +- 本进程其它线程持锁时仍走有界等待:`steer_consumption_waits_across_a_legitimate_longer_project_write`、`provider_plan_waits_across_an_autonomous_manifest_wave_project_write`、`runtime_parallel_read_projection_waits_across_a_manifest_wave_project_write`。 +- 跨进程占用与残留回收:`project_write_lock_contention_names_a_live_external_holder`、`project_write_lock_reclaims_dead_owner_pid`、`project_write_lock_reclaims_pid_reused_by_other_live_process`、`project_write_lock_reclaims_empty_body_after_short_grace`、`project_write_lock_keeps_matching_process_identity`。 +- 命令:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 project_write_lock` 全绿(含 `project::write_lock` 与 `tests::project_lock_recovery` 分组)。 +- Runner owner 的跨 AppData / 跨 boot / 恢复与诊断覆盖已经存在,并且本轮实跑通过:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- --test-threads=1 project_execution_owner` → **8 passed**(含 `project_execution_owner_is_unique_across_appdata_and_records_recovery`、`project_execution_owner_cross_boot_claim_recovers_durable_runtime_once`、`project_execution_owner_concurrent_claims_single_flight_recovery`、`tests::response_stream::project_execution_owner_cross_boot_replays_same_run_provider_handoff_to_completion_once`);`… --test-threads=1 owner_diagnostic` → **4 passed**(含 `corrupt_legacy_owner_diagnostic_does_not_block_lock_recovery`、`partial_owner_diagnostic_is_atomically_recovered_after_os_lock`)。 +- 平台边界:`project_owner_relative_open_does_not_follow_parent_replacement_race` 与 `project_execution_owner_rejects_symlinked_runtime_parent_without_touching_target` 都是 `#[cfg(unix)]`,本机(Windows)不执行,本次没有它们的证据。 diff --git a/docs/project-memory/plans/【里程碑】项目自动上传与后台工程下载-2026-09-19.md b/docs/project-memory/plans/【里程碑】项目自动上传与后台工程下载-2026-09-19.md index 15adcc42f..281b63a71 100644 --- a/docs/project-memory/plans/【里程碑】项目自动上传与后台工程下载-2026-09-19.md +++ b/docs/project-memory/plans/【里程碑】项目自动上传与后台工程下载-2026-09-19.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Version | 1.0 | -| Status | implemented-awaiting-runtime-validation | +| Status | implemented-awaiting-runtime-acceptance | | Date | 2026-09-19 | | Parent Spec | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的项目快照上传与后台工程下载合同 | @@ -21,14 +21,14 @@ ## 验收标准 -- [ ] 正式项目窗口可被同步调度识别;周期与关闭触发保持有界,失败有项目级诊断。 -- [ ] 未单独配置快照目标时仍使用 agc-dev,只复用资源存储凭据;显式快照目标保持有效,不迁移现存对象。 -- [ ] 后台列表按部署渠道查询,显示项目名/ID、用户(昵称 + 陶泥号)、同步时间、文件数、体积和完整性,支持刷新与游标分页(每页 20/50/100 + 上一页/下一页)。 -- [ ] ZIP 按清单还原相对路径;不含对象存储摘要目录;空文件可上传与导出。 -- [ ] `.agent` 承载项目身份与 Agent 状态,整目录随快照上传,并在后台 ZIP 中按原相对路径还原;归档因此可用于还原项目身份与 AGC 对话历史。凭据、版本库与构建产物仍不进快照。 -- [ ] 清单名称/完整性变化在无内容差异时也提交,partial 可恢复 ready,历史缺字段不冒充 ready。 -- [ ] 缺失、损坏、越界路径和非完整清单失败关闭;历史未声明完整性的清单明确标记,允许导出已有文件但不称为完整工程。 -- [ ] 无后台权限不能读取项目或 ZIP;不泄漏凭据;ZIP 构建有体积、并发和临时文件清理边界。 +- [x] 正式项目窗口可被同步调度识别;周期与关闭触发保持有界,失败有项目级诊断。 +- [x] 未单独配置快照目标时仍使用 agc-dev,只复用资源存储凭据;显式快照目标保持有效,不迁移现存对象。 +- [x] 后台列表按部署渠道查询,显示项目名/ID、用户(昵称 + 陶泥号)、同步时间、文件数、体积和完整性,支持刷新与游标分页(每页 20/50/100 + 上一页/下一页)。 +- [x] ZIP 按清单还原相对路径;不含对象存储摘要目录;空文件可上传与导出。 +- [x] `.agent` 承载项目身份与 Agent 状态,整目录随快照上传,并在后台 ZIP 中按原相对路径还原;归档因此可用于还原项目身份与 AGC 对话历史。凭据、版本库与构建产物仍不进快照。 +- [x] 清单名称/完整性变化在无内容差异时也提交,partial 可恢复 ready,历史缺字段不冒充 ready。 +- [x] 缺失、损坏、越界路径和非完整清单失败关闭;历史未声明完整性的清单明确标记,允许导出已有文件但不称为完整工程。 +- [x] 无后台权限不能读取项目或 ZIP;不泄漏凭据;ZIP 构建有体积、并发和临时文件清理边界。 - [ ] 定向 Rust 测试、后台类型检查/构建、UI smoke、编码、文档索引和 diff 检查完成,运行时证据与未验证部分分别列出。 ## 证据要求 @@ -60,3 +60,22 @@ 尚未替换安装版、构建新客户端发布包或部署;提交推送按用户本轮授权执行。当前条款已有上述自动化与只读存储证据,最终验收仍等待当前工作区数据库就绪后的 HTTP 联调,以及新客户端的隔离实机自动上传验证;完成后再关闭里程碑并清理两份计划。 `.agent` 全量口径已在上表取得真实上传、真实 OSS 清单与后台 ZIP 三层运行时证据。两点边界仍需记住:① 本次 smoke 用的是真实项目的可丢弃副本,其 `projectId` 改成 `gameagent-agentsmoke1`、走 dev 专用账号上传,历史真实项目在下一个同步周期前仍是旧口径清单(不含 `.agent`);② 本地 `api-server.exe` 构建于 2026-09-21 14:06,早于渠道分区提交 `4951b71d7`(2026-09-21 16:57),因此本次对象键仍是 `agc/project-snapshots/v1/` 布局、`GET /admin/api/project-snapshots/channels` 在本地返回 404;升级到 v2 键布局需要重建并重启本地 api-server。 + +## 本轮复验(2026-09-24) + +- 服务端与共享契约:`cargo test --locked -p platform-oss` → **74 passed**;`cargo test --locked -p shared-contracts` → **96 + 2 + 2 passed**;`cargo test --locked -p api-server project_snapshot -- --test-threads=1` → **21 passed / 1 ignored**。 +- 客户端:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml project_snapshot -- --test-threads=1` → **24 passed / 1 ignored**(ignored 是真实 OSS live smoke)。 +- 后台:`npm run admin-web:typecheck` 通过;`npm run admin-web:build` 成功(1820 modules,产物 579 kB / gzip 164 kB);`npx vitest run apps/admin-web/src/pages/AdminAgcTemplatesPage.test.tsx apps/admin-web/src/api/adminApiClient.test.ts` → 36 passed(列表/编辑/上传入口)。 +- 仍未验证(需要本地数据库与新客户端):`npm run dev:api-server` 就绪后的后台列表/ZIP HTTP 联调、新客户端安装版下的隔离实机自动上传。 + +## 逐条勾选依据(2026-09-24) + +- 条目 1:客户端 `project_snapshot` 定向 24 passed,含 `project_snapshot_workspace_lifecycle_tracks_the_single_client_window`、`project_snapshot_exit_wait_includes_scheduled_tasks_waiting_for_the_project_lock`、`project_snapshot_periodic_trigger_yields_while_a_sync_is_in_flight`。 +- 条目 2:`config::tests::from_env_project_snapshot_target_is_independent_and_only_credentials_fallback`、`project_snapshot_channel_follows_client_download_channel_unless_overridden`(api-server 侧)。 +- 条目 3:后台列表/分页用例 `project_snapshots_pagination_continues_directories_without_rescan`、`project_snapshots_items_resolve_author_profile_for_admin_list` + 后台页面 36 项 Vitest(渠道查询、分页 20/50/100)。 +- 条目 4:`project_snapshots_upload_accepts_empty_files_and_rejects_false_checksums`、`project_snapshots_zip_restores_paths_and_empty_files`。 +- 条目 5:`project_snapshot_scan_uploads_whole_agent_directory`、`project_snapshot_sync_policy_keeps_agent_state_and_still_blocks_credentials` + 后台 ZIP 用例。 +- 条目 6:`project_snapshot_manifest_metadata_changes_sync_without_content_changes`、`project_snapshot_legacy_index_keeps_completeness_unknown`、`project_snapshots_status_preserves_unknown_and_partial`。 +- 条目 7:`admin_project_snapshots::tests::project_snapshots_archive_rejects_ambiguous_paths_and_unsafe_names`、`project_snapshots_zip_fails_closed_and_cleans_tempfiles`。 +- 条目 8:`admin::agc_model_permissions_tests::project_snapshots_handlers_require_the_tab_for_authenticated_members`、`project_snapshots_response_releases_file_and_permit_on_finish_or_cancel`、`project_snapshots_cancelled_wait_keeps_permit_until_blocking_work_exits`;`platform-oss` 74 passed 覆盖凭据不下发与有界读取。 +- 未勾选的条目 9:UI smoke 与「运行时证据/未验证部分分别列出」还差本地数据库就绪后的 HTTP 联调与新客户端实机自动上传,保持未勾选。 diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 6aee441ad..740db9935 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -21,7 +21,7 @@ - 背景:游戏广场发行包上限原为 100 MiB(`module-game-distribution` 的 `MAX_PACKAGE_BYTES` 与网页端 `GAME_PACKAGE_MAX_BYTES`),而 Nginx 三份模板与 Pingora 网关的通用 `/api` 放行量是 64 MiB。上限只改一层没有意义:包体超过 100 MiB 时先在反代层被 413,`api-server` 的 ZIP 校验根本不会执行。 - 决策:发行包上限 100 MiB → 200 MiB;展开总量 250 MiB → 500 MiB(保持 2.5 倍余量);单文件 64 MiB、最多 10,000 个文件、展开/压缩比 100 三条内容规则不变;发行包路由请求体上限继续从包上限派生(200 MiB + 1 KiB)。反代放行量统一放宽到 210 MiB:`deploy/nginx/genarrative.conf`、`deploy/nginx/genarrative-dev-http.conf`、`deploy/container/nginx.conf` 使用 `client_max_body_size 210m`,Pingora `DEFAULT_MAX_API_BODY_BYTES` 改为 `220200960` 并同步 `deploy/pingora/pingora-gateway.env.example`。发行静态资源进程内缓存字节预算 200 MiB → 256 MiB,让 200 MiB 档发行包仍能进缓存、且不独占整份预算。 -- 边界:包内单个文件仍不得超过 64 MiB;线上 Pingora 环境文件若仍写 `67108864`,必须在重启网关前同步改值,否则发行包 PUT 会在网关层被 413。AGC 一键发布经 `@tauri-apps/plugin-http` 传整包字节,实际可发布体积还受该传输方式限制,200 MiB 档的客户端容量需要单独验证。 +- 边界:包内单个文件仍不得超过 64 MiB;线上 Pingora 环境文件若仍写 `67108864`,必须在重启网关前同步改值,否则发行包 PUT 会在网关层被 413。AGC 一键发布经 `@tauri-apps/plugin-http` 传整包字节,实际可发布体积还受该传输方式限制,200 MiB 档的客户端容量需要单独验证。(2026-09-24 更正:一键发布已改为 Rust 侧分片续传,不再经渲染层的 `@tauri-apps/plugin-http`;渲染层 HTTP 权限与插件一并退役,200 MiB 档的客户端容量仍需单独验证。) - 影响范围:`server-rs/crates/module-game-distribution/src/package.rs`、`server-rs/crates/api-server/src/modules/game_distribution.rs`、`server-rs/crates/pingora-gateway/src/main.rs`、`src/components/game-distribution/gameZipPackage.ts`、`deploy/{nginx,container,pingora}`、`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`、`docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md`。 - 验证方式:`cargo test -p module-game-distribution`(13 passed,其中 `accepts_package_above_the_previous_hundred_mib_limit` 用两个 50 MiB 存储型条目构造 100 MiB 出头的包;把上限临时改回 100 MiB 时该用例确实失败,证明它能守住新上限)、`cargo test -p api-server game_distribution`(20 passed,含新增的请求体上限覆盖包上限断言)、`cargo test -p pingora-gateway`(38 passed,含 `matches_nginx_route_parity_matrix`)、`npx vitest run src/components/game-distribution`(46 passed)、`cargo fmt --all -- --check`、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` 通过。`npm run check:pingora-route-parity` 仍在 dev-http / 容器模板缺少 `/games` 等 SPA 路由处失败,改动前同样失败,与本次口径无关。200 MiB 档真实栈容量证据(上传耗时、api-server 峰值内存、超限 413 口径)尚未复跑,发布前需按阶段 D 脚本重跑一轮。 @@ -35,7 +35,7 @@ - 原因:不改反解析是因为粘贴解析与润色回包共用 `buildContentFromTextTokens`,改匹配算法要冒回归润色的风险;而「名字里带空白的 token」本来就无法手敲(候选触发器 `allowWhitespace: false`,空格处菜单就关),显示口径与输入口径早就不一致。折成 `-` 之后 token 自带边界:`@hero` 不会命中 `@hero-v2`(后一个字符是 `-`,不是空白),前缀重叠不可能再发生。 - 影响范围:`apps/ai-game-creator-shell/src/features/project-workspace/{resourceReferences.ts,reference-source/{skillReferenceProvider.ts,attachmentReferenceProvider.ts}}`、`apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directCodexTurnAttachments.ts`、`apps/ai-game-creator-shell/tests/{resourceReferences.test.ts,referenceSourceProviders.test.ts}`、`CONTEXT.md`、`docs/【功能说明】AGC聊天素材引用-2026-09-08.md`、`docs/project-memory/plans/【实施计划】引用粘贴解析-2026-09-22.md`。 - 代价(已接受):归一化可能撞名(`hero v2` 与 `hero-v2` 同名),走既有的「同名多候选一律按文本保留」——不认错,但两者都成不了芯片;改动前生成的旧文本(历史回合 prompt、旧气泡)里的 `@hero v2` 不再解析,重试 / 润色回填时那条引用会退化成末尾孤儿(内容不丢、位置可能不对)。 -- 验证方式:`normalizeMentionName`、`resourceDisplayName`、`chatReferenceMentionToken` 的口径单测;「空白折 `-` 后 token 自带边界、前缀重叠只剩正确芯片」的回归用例;Skill 目录名带空白与附件名带空白的 provider 用例;把 `normalizeMentionName` 变异成恒等函数后以上新增用例全部变红。另跑受影响用例、`npm run typecheck`、`npm run check:encoding`、`git diff --check`。 +- 验证方式:`normalizeMentionName`、`resourceDisplayName`、`chatReferenceMentionToken` 的口径单测;「空白折 `-` 后 token 自带边界、前缀重叠只剩正确芯片」的回归用例;Skill 目录名带空白与附件名带空白的 provider 用例;把 `normalizeMentionName` 变异成恒等函数后以上新增用例全部变红。(2026-09-24 独立复核:把 `normalizeMentionName` 改成 `return value` 后,`resourceReferences.test.ts` + `referenceSourceProviders.test.ts` + `resourceReferenceInput.test.tsx` 三个文件共 5 条失败、74 条通过,声明成立。)另跑受影响用例、`npm run typecheck`、`npm run check:encoding`、`git diff --check`。 ## 2026-09-22 引用粘贴解析:只认显示口径的 token,宁可不成芯片也不能认错 @@ -73,7 +73,7 @@ - 保留项:命令 id 注册表 `GAME_CREATION_APP_COMMANDS` 与 `GameCreationAppPermission`(项目权限策略词汇表;App 前端只用 `GameCreationAppCommandDescriptor` 类型表达权限判定与审计粒度,数组本体由 Rust 策略路径消费)、`needsInitializedChatProject`,以及 `--agent-run` / `--agent-enqueue` / `--agent-steer` / `--agent-resume` / `--agent-context-compact` 等非聊天 CLI 控制命令与 Tauri IPC 注册。 - 影响范围:`apps/ai-game-creator-shell/src/**`(Direct 聊天控制器、润色、`project-summary`、`project-workspace`)、`src-tauri/src/**`(`cli.rs`、`main.rs`、`swarm_cli` 整目录删除、`agent/interaction.rs` 收敛、命令注册、canvas 生成、provider / project 测试)、`apps/ai-game-creator-shell/scripts/agent-runtime-real-e2e/**`、`scripts/check-config.mjs`、root 与 App 的 `package.json` 脚本、`tests/**`,以及 AGC 主实施计划文档、Runtime V1.1 文档与 `CONTEXT.md` 术语。 - 验证方式:`npx tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit`、`npm run --workspace apps/ai-game-creator-shell typecheck`(含 `check-config.mjs` 的脚本与门禁一致性)、`npx vitest run apps/ai-game-creator-shell/tests/appSurface.test.ts`、`cargo check --tests`(告警消息集与基线一致)、`npm run check:encoding`、`git diff --check`;保留的 e2e 套件为 `supervisor-swarm`、`-transient-retry`、`-final-reply-transient-retry`、`-tool-plan-handoff-runner-kill`、`goal-runtime`、`response-stream`、`web-search`、`context-compaction`、`scoped-agents`、`project-skill`、`parallel-read`、`steer-runner-kill`、`process-session`。 -- 关联文档:[【ADR】退役AGC项目对话斜杠命令与终端swarm chat入口-2026-09-22](../../adr/【ADR】退役AGC项目对话斜杠命令与终端swarm chat入口-2026-09-22.md)、[【里程碑】退役AGC项目对话斜杠命令与终端swarm chat入口-2026-09-22](../plans/【里程碑】退役AGC项目对话斜杠命令与终端swarm chat入口-2026-09-22.md)、`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`。 +- 关联文档:[【ADR】退役AGC项目对话斜杠命令与终端swarm chat入口-2026-09-22](../../adr/【ADR】退役AGC项目对话斜杠命令与终端swarm chat入口-2026-09-22.md)、`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`。(2026-09-24:对应里程碑已完成并删除,结论以 ADR 为准。) ## 2026-09-23 AGC 发布资料免费生成与封面泥点生成 @@ -277,7 +277,7 @@ - 根因:同一条链路里存在两个不同的切片上限。平台切分是 256(`server-rs/crates/api-server/src/editor_project_icon.rs` 的 `EDITOR_ICON_SPRITESHEET_MAX_SLICES`),Agent 工具 schema 的 `sliceCount` 是 1..256(`agent_native_tools.rs` / `direct_tool_bridge.rs`),持久化产物批次也是 1..256,公开契约(`docs/【编辑器】画板图标素材生成入口设计-2026-06-15.md`)写的更是「最多 256 个输出」;唯独客户端**两处结果绑定门**还是 `> 64` 就拒(`agent/generation/external_generation_state.rs` 与 `agent/generation/canvas_generation.rs`,由 `602723ea0` 于 2026-08-03 引入)。自动切分落在这个窗口里(65~256 片)时,客户端比平台更严,于是把合法产出整条丢掉。 - 决策:两处门统一到 `PLATFORM_ART_SPRITESHEET_MAX_SLICES = 256`,并抽成同一条判据 `platform_art_spritesheet_slice_count_exceeds_limit` 与同一句拒绝文案 `platform_art_spritesheet_slice_limit_error`(数字由常量插值,不再手写)。注释里点名三处同值权威(平台切分常量、工具 schema `sliceCount`、公开契约),客户端不得比平台更严。 - 原因:客户端这两处门的作用是「防止把不可信/超预算的结果写进本地」,不是产品上限;真正的产品上限属于平台切分契约。两处各写一个字面量就会再次漂移,所以值只留一份、判据只留一条。 -- 验证:新增 `canvas_generation_tests::spritesheet_slice_limit_matches_platform_and_tool_contract`(上限值、边界判据与文案)与 `external_generation_state_tests::legacy_result_accepts_slice_counts_up_to_platform_limit_and_rejects_beyond`(64/65/256 片必须能持久化且切片一条不少、257 片必须按同一句文案拒绝),两条都用**变异验证**确认过:把常量改回 64,回归用例立刻变红。定向执行 `cargo test -- spritesheet`(22 passed)、`cargo test -- external_generation_state_tests::`(10 passed)与两条新用例;`cargo fmt --check` 干净。 +- 验证:新增 `canvas_generation_tests::spritesheet_slice_limit_matches_platform_and_tool_contract`(上限值、边界判据与文案)与 `external_generation_state_tests::legacy_result_accepts_slice_counts_up_to_platform_limit_and_rejects_beyond`(64/65/256 片必须能持久化且切片一条不少、257 片必须按同一句文案拒绝),两条都用**变异验证**确认过:把常量改回 64,回归用例立刻变红。(2026-09-24 独立复核:把 `PLATFORM_ART_SPRITESHEET_MAX_SLICES` 改成 64 后,`spritesheet_slice_limit_matches_platform_and_tool_contract` 报 `left: 64 / right: 256`、`legacy_result_accepts_slice_counts_up_to_platform_limit_and_rejects_beyond` 同样变红;改回 256 后 `cargo test -- spritesheet` 与那条 legacy 用例各自 exit 0,`cargo fmt -- --check` 通过。)定向执行 `cargo test -- spritesheet`(22 passed)、`cargo test -- external_generation_state_tests::`(10 passed)与两条新用例;`cargo fmt --check` 干净。 - 影响范围:`apps/ai-game-creator-shell/src-tauri/src/agent/generation/{canvas_generation.rs,external_generation_state.rs}`(+用例)。未动平台切分、OpenAPI、数据库或前端。 - 已知未覆盖:真实客户端复验(重新生成一次图标素材)与远程 CI 未跑;256 片时的累计下载/像素预算未实测——平台自己的总像素上限是 2048×2048,客户端预算是 4096²,按切片是整图互不重叠子矩形推算不会先撞预算,且真撞了也只是给出明确错误而不是损坏数据。 @@ -437,7 +437,7 @@ Godot 编辑器操控复用既有 AGC 插件宿主、EditorAdapter、Runner 和 - 决策(残留清理):随面板一起失去调用方的模块与导出一并删除,不留死代码——`features/project-workspace/projectSummaryCommands.ts`(旧 Supervisor 斜杠命令处理器,1054 行)、`app/constants.ts` 的 `AGENT_RUN_HISTORY_*`、`features/agent-runtime/model.ts` 里只被退役面板使用的 22 个导出与 `AGENT_RUNTIME_DEDICATED_CARD_TOOLS`、`features/project-summary/agentPresentation.ts` 里 17 个 Agent 面板 / LLM 配置 / 读取草稿摘要函数(含 `summarizeAgentStatusCardsForChat`、`summarizeAgentRunHistoryReadDrafts` 等),以及 `agentRunTrace` / `memoryCommands` / `projectCommandPolicy` 中失去调用方的校验与解析函数。 - 边界:后端 Rust Runtime 的 `project-supervisor` 运行身份、`start_game_creator_supervisor_runtime_task` 命令、`agent-runtime:supervisor-*` 端到端脚本与 `project-supervisor` 提示词/工具策略不在本次删除范围内:它们是 Runtime 的 Agent 身份与既有权衡,不是前端链路。 - 验证:全量 `npx vitest run apps/ai-game-creator-shell/tests` 126 失败 / 1517 通过 / 15 跳过(1658 条),`HEAD` 基线同口径 166 失败 / 1637 通过 / 17 跳过(1820 条):逐条比对失败集合**没有新增项**;基线里 40 条与 Supervisor 前端面绑定的失败用例随实现与用例一并删除(含旧调试窗口、开发者面板与 Agent 对话浮层的 51 条用例);剩余 115 条 appSurface 失败与 10 条 `clientApi.test.ts` 失败(jsdom `localStorage` 环境)在基线上同样失败;残留清理后按同一口径复跑,失败集合与失败条数均无变化。`npx tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit --noUnusedLocals`、prettier、eslint、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` 通过。 -- 关联文档:[ADR DirectProject 独立聊天容器与工作台钱包布局](../../adr/【ADR】DirectProject独立聊天容器与工作台钱包布局-2026-09-18.md)、[实施计划](../plans/【实施计划】DirectProject聊天模块抽离-2026-09-18.md)。 +- 关联文档:[ADR DirectProject 独立聊天容器与工作台钱包布局](../../adr/【ADR】DirectProject独立聊天容器与工作台钱包布局-2026-09-18.md)。(2026-09-24:对应开发期里程碑与实施计划已按代码级判据验收归档并删除,结论以该 ADR 为准。) ## 2026-09-19 DirectProject 聊天容器按「组件带逻辑」分层,线程订阅与 reducer 提成独立 hook @@ -447,7 +447,7 @@ Godot 编辑器操控复用既有 AGC 插件宿主、EditorAdapter、Runner 和 - 决策(壳只传窄上下文):`DirectProjectChatView` 的公开入参只有项目路径、入口首轮需求(canonical `content[]`)和两条权限门;工作台级动作(`game.run_local` 预览结果等)不再写 `App.tsx` 的 `messages`,改由壳通过 `DirectProjectChatHandle.announce` 交给聊天自己的本地消息流,壳不持有 Direct 聊天消息。 - 边界:不改 Tauri/Rust 命令、DTO、Thread Manager、Codex app-server、持久化事实源、路由选择、发送/队列/附件/中止/历史锚点语义;不保留旧路径 alias、双跑或兼容 fallback。 - 验证:五个 Direct 纯模块测试 40 条通过;`appSurface.test.ts -t "direct"` 15 通过 / 4 失败,4 条与 `HEAD` 同口径基线同为失败(harness 未桩模型配置),基线同口径 14 通过 / 5 失败;全量 `appSurface.test.ts` 由基线 155 失败降到 153 失败;app `tsc --noEmit`、eslint、prettier 通过。 -- 关联文档:[ADR DirectProject 独立聊天容器与工作台钱包布局](../../adr/【ADR】DirectProject独立聊天容器与工作台钱包布局-2026-09-18.md)、[实施计划](../plans/【实施计划】DirectProject聊天模块抽离-2026-09-18.md)。 +- 关联文档:[ADR DirectProject 独立聊天容器与工作台钱包布局](../../adr/【ADR】DirectProject独立聊天容器与工作台钱包布局-2026-09-18.md)。(2026-09-24:对应开发期里程碑与实施计划已按代码级判据验收归档并删除,结论以该 ADR 为准。) ## 2026-09-18 Provider 瞬态重试次数严格按设置执行(游戏开发 Agent 与策划 Agent 不再被档位收进区间) @@ -725,7 +725,7 @@ Godot 编辑器操控复用既有 AGC 插件宿主、EditorAdapter、Runner 和 - 连带维护点:`scripts/git-hooks.test.mjs` 用 `assert.deepEqual` **钉住 lint-staged 的整份配置形状**,增键必须同步该用例,否则 `check:git-hooks`(在 `npm run lint` 内)会以 `deepStrictEqual` 失败 —— 本次就是这样红了 Repository checks。该文件第 2 个用例里的 `lintStagedConfig` 是 temp repo 的测试替身,不随之增键:temp repo 没有 Rust 文件,`.rs` 只会命中 0 个。 - 已知影响(**刻意保留**):没有暂存 `.rs` 时守卫完全不触发(lint-staged 报 `[SKIPPED] *.rs — no files`);一旦暂存了 `.rs`,它检查的是**整个 workspace** 而不只是暂存文件 —— 这是为了与 CI 完全同口径而接受的取舍,副作用是「别人工作树里未格式化、且尚未暂存的 `.rs` 会挡住本次提交」,此时应按报错里的文件去找该文件的作者,不要顺手 `cargo fmt`(那会连带格式化别人的在途代码)。**裁定:保持「整个 workspace」不变**,不换成「只查暂存文件」(`rustfmt --check --skip-children` 与 `cargo fmt` 的口径不再一致)。理由是「本地绿 ≠ CI 绿」正是本批两次 CI 红的共同根因,守卫必须与 CI 走同一条口径;共树里那种硌人是**共享 worktree 的症状、不是守卫的问题**,对应的流程修正是「一条线一个 worktree」。 - 已知本地限制(**本机环境限制,不是「CI 会红」**):`check:git-hooks` 第 2 个用例(`pre-push runs repository parity only for master updates`)在 Windows 本机会红,形态是 `finally` 里 `rmSync` 报 `EBUSY: resource busy or locked`(**断言全部通过,红在清理**)。根因是 Windows/WSL 跨 `/mnt/c` 的临时目录句柄在子进程退出后仍被持有(本机 `bash` 是 WSL 的 GNU bash 5.2.21 `x86_64-pc-linux-gnu`),该句柄存活时间超过删除重试窗口 —— 给 `rmSync` 加 `maxRetries: 10`(约 5.5s 线性退避)实测**无效**,已逐字还原。**后果是残留目录会累积**:清理前本机 `%TEMP%` 有 16 个 `genarrative-pre-push-*`、最早到 2026-09-05(即每次运行都发生;本轮已清到 0),看到残留目录直接删即可。判定它是本机环境限制而非 CI 会红的依据:残留目录已持续一周,而这一周 CI 上该用例是绿的 ⇒ **Linux CI 上该用例通过**。**裁定:接受它在 Windows 上红,不改该用例语义、本批不再修。** -- 验证方式:`node scripts/lint-staged-rustfmt.mjs` exit 0;lint-staged 分派层面确认 `*.rs` 任务真被触发(对 6 个 `.rs` 跑通)且无 `.rs` 时 `[SKIPPED]`;`npm run check:rustfmt`、`npm run check:encoding`、`git diff --check` 均 exit 0。变异验证:把 `*.rs` 从 `package.json` 摘掉 → `check:git-hooks` 第 1 个用例以同样的 `deepStrictEqual` operator 变红;还原(`package.json` 字节级哈希一致)后该用例回 `ok`。 +- 验证方式:`node scripts/lint-staged-rustfmt.mjs` exit 0;lint-staged 分派层面确认 `*.rs` 任务真被触发(对 6 个 `.rs` 跑通)且无 `.rs` 时 `[SKIPPED]`;`npm run check:rustfmt`、`npm run check:encoding`、`git diff --check` 均 exit 0。变异验证:把 `*.rs` 从 `package.json` 摘掉 → `check:git-hooks` 第 1 个用例以同样的 `deepStrictEqual` operator 变红;还原(`package.json` 字节级哈希一致)后该用例回 `ok`。(2026-09-24 独立复核:摘掉 `*.rs` 那段后 `check:git-hooks` 第 1 个用例报 `operator: 'deepStrictEqual'`、本次运行 `# pass 1 / # fail 1`;从备份还原后 `package.json` SHA256 与改前逐字节一致(`A205E54E…`)且 `check:git-hooks` exit 0。) - 关联文档:`docs/project-memory/shared-memory/pitfalls.md`(`cargo fmt --all` 会扫到别人未提交半成品那条)。本文件 2026-08-12「Repository checks 采用 CI 与本地共用的单一门禁入口」条的「提交门禁」一行只描述当时的 JS/TS 范围,按本文件顶部口径历史条目只用于追溯,不再回改;提交 `dd7cf401a`(守卫本体)、`2a7bfadd7`(形状断言跟进)。 ## 2026-09-11 冷启动首屏存在同一张卡被读两次(登记回声 + 取消/重扫路径):记录为后续项,本轮不修 @@ -8233,7 +8233,7 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在 ## 2026-08-10 AGC 普通 release 固定连接 dev API -- 传输边界:dev 公网入口不接受 Tauri WebView 的跨域 OPTIONS 预检,因此 release 使用 `tauri-plugin-http` 原生 transport。插件的 npm 依赖只归属 AGC 子包及其 lockfile,根 H5 package 与根 lockfile 不得引入任何 Tauri guest 依赖。插件 capability 与前端 URL 解析双重限制为 `https://dev.genarrative.world/api/*`,不为 WebView CSP 增加远程 `connect-src`,也不开放任意 HTTP(S) 目标。 +- 传输边界:dev 公网入口不接受 Tauri WebView 的跨域 OPTIONS 预检,因此 release 使用 `tauri-plugin-http` 原生 transport。插件的 npm 依赖只归属 AGC 子包及其 lockfile,根 H5 package 与根 lockfile 不得引入任何 Tauri guest 依赖。插件 capability 与前端 URL 解析双重限制为 `https://dev.genarrative.world/api/*`,不为 WebView CSP 增加远程 `connect-src`,也不开放任意 HTTP(S) 目标。(2026-09-24 更正:该传输结论已作废——渲染层不再持有 HTTP 通道,`capabilities/main.json` 的 `http:default` 作用域、`tauri-plugin-http` 插件注册与 npm guest 全部删除,平台 IO 由 Rust reqwest facade 承担;WebView CSP 仍不为平台域增加远程 `connect-src`。) - 会话边界:插件默认 Cookie Store 持久化 refresh Cookie;访问 Token 继续保存在现有客户端存储并通过 Authorization header 发送,不把 Token、Cookie 或登录正文写入日志、配置文件或仓库。 ## 2026-08-10 AGC monorepo 构建强制复用单一 React runtime @@ -8300,7 +8300,7 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在 - AGC 登录页提供 `release`(`https://www.genarrative.world`)、`dev`(`https://dev.genarrative.world`)和 `custom` 三种服务器选择;选择持久化在客户端本地存储,登录、验证码、刷新和原生平台会话安装统一使用当前选择。 - custom 只接受纯 HTTPS origin;`localhost` / loopback 的 HTTP 也允许用于本机服务,禁止把路径、查询参数、凭据或非本机明文 HTTP 地址作为服务器地址。 -- Tauri release 的 HTTP capability scope 必须覆盖 release、dev、custom HTTPS 以及 loopback HTTP,`check:native-shells` 以该精确 allowlist 作为源码门禁;否则前端选择虽能保存,plugin-http 仍会在请求层拒绝登录。 +- Tauri release 的 HTTP capability scope 必须覆盖 release、dev、custom HTTPS 以及 loopback HTTP,`check:native-shells` 以该精确 allowlist 作为源码门禁;否则前端选择虽能保存,plugin-http 仍会在请求层拒绝登录。(2026-09-24 更正:渲染层已无 plugin-http,登录由 Rust 发请求;`check:native-shells` 的这条精确 allowlist 断言已改成负向门禁——任何 capability 都不得授予 `http:default`,且渲染源码不得出现 `fetch(` / `XMLHttpRequest` / `EventSource` / `sendBeacon(` / `new WebSocket(` / `@tauri-apps/plugin-http`。) - 直连 Codex 的本机 External Editor API Key 必须按服务器 origin 独立存储。登录服务器切换后禁止复用另一 origin 的历史 Key 或 base URL;否则会出现登录走新服务器、平台资源生成仍请求旧服务器的漂移。 ## 2026-08-18 AGC 登录网络错误与 Web Build 门禁对齐 @@ -9084,7 +9084,7 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在 - 背景:长回合保活和 401 续期每次签发新 access token,并推进 native generation 重新安装原生会话;冻结平台会话同时比对身份与 token 字节,于是同账号的正常续期被等价成换号,并发在途的生成 / 编辑 / 上传 / 确认 / 下载 operation 全部被判为“旧账号请求”失败。更彻底的一层是原生会话、Runner attach 与 renderer 代次都把“写入顺序”和“身份归属”压在同一个计数器上。 - 决策:平台会话拆成身份(`userId + api origin + identity generation`)与凭据(当前 access token)。identity generation 只在登录、切号、登出或新的 GUI authority epoch 推进;同账号续期只更新凭据并推进只用于拒绝迟到写入的 revision。冻结会话校验、MCP 会话身份与 Runner attach 统一按身份判定,换号 / 退出仍然失败关闭。刷新失败只在服务端明确 401/403 且一次收敛重试后仍失败时清会话;`/api/auth/refresh` 的轮换失败不再下发清空 refresh cookie 的响应。 -- 关联规范:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的“2026-09-16 平台会话身份与凭据分离”;开发期计划见 `docs/project-memory/plans/【里程碑】平台会话身份与凭据分离-2026-09-16.md` 与对应实施计划。 +- 关联规范:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的“2026-09-16 平台会话身份与凭据分离”(原开发期里程碑与实施计划已按其结论验收归档并删除)。**2026-09-24 修订**:渲染层那半(`platformSession` 的身份代次与 native revision 状态机、`clientAuth` 的 token 续期)已由 Rust `auth_session` 取代——凭据持久化、续期 HTTP 与原生会话安装都归 Rust,渲染层只剩「身份代次投影 + 事件订阅」;身份/凭据/revision 三分判据本身不变,仍由 Rust `platform_session` 强制。 - 验证:AGC `platform_session::tests`、`runner::tests`、`assets::tests` 定向通过;AGC `appSurface` 前端套件 468 项通过;网站 `src/services/apiClient.test.ts` 33 项通过;`cargo test -p api-server refresh_session` 通过。项目夹具类 Rust 用例受本机临时目录属主为 `BUILTIN\Administrators` 的环境限制,未计入本次证据。 ## 2026-09-15 Direct 回合跨页面继续运行与活动项目面板 @@ -9105,7 +9105,7 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在 - 决策:清单 schema 为 `agc-template-library.v1`,每条模板带 `tags`、`coverKey/coverWidth/coverHeight/coverSha256`、`zipKey/zipSizeBytes/zipSha256` 与 `templateVersion`;客户端只信「受信任 OSS 主机 + 对象键」自行拼 URL,清单里的地址字段不参与请求。 - 决策:客户端缓存与安装根为 `/templates/`(`index.json` 缓存 + `installed///`,安装完成才写 `installed.json`);建项目在 `/projects/` 下走既有自动工作区规则,先铺模板文件再补 `.agent` 清单。 - 决策:模板库首页推荐位替换原「灵感推荐」本机图片目录(已删除 `InspirationGallery.tsx` 与 `assets/inspiration/`);左侧导航新增模板库入口,打开独立全屏页。`tauri.conf.json` 的 `img-src` 放行受信任 OSS 主机用于封面图。 -- 关联规范:`docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`;开发期计划见 `docs/project-memory/plans/【里程碑】AGC模板库客户端接入-2026-09-17.md` 与对应实施计划。 +- 关联规范:`docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`(2026-09-21 验收通过并已删除对应开发期里程碑,结论以该技术方案为准)。 - 验证:Rust 模板库 8 项定向单测、前端模型 9 项单测、AGC `tsc` 类型检查通过;`templates/index.json` 匿名可读且每个 `zipKey` 回读 SHA-256 与清单一致;发布脚本 `scripts/agc-template-library-publish.mjs` 支持 `--dry-run` 与上传后回读校验。 ## 2026-09-16 DirectProject 上传文件统一使用附件 content part @@ -9122,7 +9122,7 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在 - 原因:`3c7b02b9f` 为了让 content 通过「空 `input_text`」校验而在投影层丢空白 part,把引用后的段落分隔一起丢了(`@素材` 与下一段粘成一个词);`41366dd71` 又把消息 / 队列 / 快速编辑的文本派生切到这条投影上,缺陷扩散到界面与出站 prompt。 - 边界:不新增 content part 类型,不迁移历史(历史 content 原样回放),不为旧口径保留兼容分支;前端仍不发整条全空白的一轮,app-server 输入里出现纯空白 text item 由本决定接受。 - 验证:Rust `validation.rs` / `wire.rs` 用例「单个纯空白 part 通过校验、整条全空白拒绝」;AGC 侧 `resourceReferenceInput.test.tsx`、`resourceReferences.test.ts`、`appSurface/project-development.suite.ts`(Godot 回合)、`projectResourceLiveIntegration.test.tsx` 改为按逐字投影断言,`ai-game-creator-shell:typecheck` 与定向 vitest 通过。 -- 关联规范:`docs/project-memory/plans/【里程碑】DirectProject canonical content严格边界-2026-09-16.md`。 +- 关联规范:`docs/【功能说明】AGC聊天素材引用-2026-09-08.md`。(2026-09-24:canonical content 严格边界与 composer 闭环两份开发期里程碑已按其结论验收归档并删除。) ## 2026-09-16 CI 宿主 CPU 上限:Jenkins 16 核 / Gitea Actions runner 12 核 @@ -9171,11 +9171,11 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在 - 背景:首页「做游戏 / 做方案」与模板库「使用模板」的自动建项固定落在 `/projects`,用户无法把游戏放到自己的工作盘或工程目录;同时该路径不能随意放开(受管私有目录门禁与 Documents 继承 ACL 的既有约束见 `pitfalls.md`)。 - 决策:新增可选参数 `projectsRoot`(`create_automatic_local_game_project`、`create_automatic_local_game_project_from_template`),为空时由 Rust 回落到 `/projects`。可选值只接受本机原生目录选择器返回的目录:`validate_requested_game_project_creation_root` 要求非空绝对路径、无控制字符、已存在的普通目录(拒绝链接/reparse point),并通过 `prepare_game_creator_project_root_for_read` 的 user-selected 范围校验与一次性修复;目录不存在不代为创建。 -- 决策:客户端偏好「项目创建目录」存 `localStorage` 键 `genarrative-ai-game-creator.project-creation-directory.v1`;入口只在设置里(侧边栏「配置」→ 分类「工作区」),首页输入行与模板库页头不再各挂一个入口。「恢复默认位置」即清空偏好。偏好只表达用户意图,不是授权凭据:每次建项都重新过 Rust 门禁,存储被改坏最坏是回退默认位置或一次可见失败。既有项目不迁移。 +- 决策:客户端偏好「项目创建目录」的入口只在设置里(侧边栏「配置」→ 分类「工作区」),首页输入行与模板库页头不再各挂一个入口;「恢复默认位置」即清空偏好。偏好只表达用户意图,不是授权凭据:每次建项都重新过 Rust 门禁,存储被改坏最坏是回退默认位置或一次可见失败。既有项目不迁移。**2026-09-23 修订**:偏好改由 Tauri Rust AppData `workspace-preferences.json` 持有(typed command + 变更事件),渲染层不再读写 `localStorage`;建项命令也不再从渲染层接收 `projectsRoot`,改由 Rust 读取已存偏好后执行同一套门禁。 - 决策:该偏好属于客户端本地设置,不并入 `read_game_creator_app_config` 那份运行时配置:在「工作区」里选择目录当场生效,不受「保存设置」按钮影响;首页与模板库建项时各自读取同一份偏好。 - 决策:`pick_local_project_directory` 增加可选 `title`(限 24 字符、无控制字符,其余回退默认标题),使「选择项目创建目录」不再冒用「选择游戏项目目录」文案。 -- 关联规范:`docs/project-memory/plans/【实施计划】AGC项目创建目录可选-2026-09-17.md`、`docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`。 -- 验证:`cargo test --bin genarrative-ai-game-creator-shell creation_root`(2 项)、模板库定向单测 14 项、偏好模型 3 项、`appSurface` 472 项(含设置页「工作区」选择/恢复目录与「设置里选目录后建项带 `projectsRoot`」两条场景)、`tsc`、`check:encoding` 与 `check-doc-index` 通过。 +- 关联规范:`docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`(原实施计划已于 2026-09-24 完成并删除,机制修订见上一条)。 +- 验证:`cargo test --bin genarrative-ai-game-creator-shell creation_root`(2 项)、模板库定向单测 14 项、偏好模型 3 项、`appSurface` 472 项(含设置页「工作区」选择/恢复目录与「设置里选目录后建项」两条场景;2026-09-24 起建项调用不再携带 `projectsRoot`,改由 Rust 读偏好)、`tsc`、`check:encoding` 与 `check-doc-index` 通过。 ## 2026-09-20 Rust 工具链升到 1.98.1:仓库侧四处同步 + runner 镜像必须重建 @@ -9309,3 +9309,31 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在 - 影响范围:`server-rs/crates/api-server/src/admin.rs`(新增 schema 解析与 `build_admin_database_enum_labels`,删除 `normalize_admin_database_known_enum`,`parse_admin_database_table_rows_sql_response` / 行构建与归一化改为接收枚举映射)、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`、`.codex/skills/genarrative-admin-backoffice/references/spacetimedb-http-sql-sats-display.md`。前端与 DTO 不变。 - 验证方式:`cargo test -p api-server --manifest-path server-rs/Cargo.toml --bin api-server admin::tests`(86 passed,含新增 `admin_database_enum_labels_come_from_schema_variants` 与改写后的充值订单枚举用例);用本地 dev schema 逐表回放同一算法,85 张表里 32 个枚举列全部解析出展示名、0 个残留;`cargo check -p api-server`、`cargo fmt --all --check`、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` 通过。 - 边界(未验证):没有对真实 HTTP 表查询响应做端到端比对(本地 dev api-server 仍是改动前二进制,未重启)。 + +## 2026-09-24 根 vitest include 白名单补齐现役模块测试 + +- 背景:`e9c3dc112` 把 `src/**/*.test.ts(x)` 与 `packages/shared/src/**/*.test.ts(x)` 的通配 include 收成显式白名单(退役旧创作模板业务的配套动作)。白名单只列了当时确认存活的目录,导致 8 组**现役**模块的用例从此不在任何门禁里执行:`src/services/sseStream.test.ts`(SSE 传输层收口约定写明的验收)、`src/services/frontendRuntimeConfigService.test.ts`、`src/persistence/**/*.test.ts`、`src/routing/RouteImageReadyGate.test.ts`、`src/editor/shared/jsonClient.test.ts`、`src/components/platform-entry/PlatformProfilePrimitives.test.tsx`、`packages/shared/src/theme.test.ts`、`apps/ai-game-creator-shell/src/features/ui-editor/utils/transform/tf2css.test.tsx`。用临时配置把它们收进来实跑:261 个文件 / 2683 条全绿,只有 4 条断言旧像素弹窗壳(该壳在 `7ea463ed0` 已退役)失败。 +- 决策:把这 8 组现役用例补回根 `vitest.config.ts` 的 include,**不**恢复 `src/**` 通配——旧创作链路的退役测试(`src/components/common/**` 下大量只剩兼容导出、无现役调用方的测试)继续不收集,等清理该目录时连同实现一起删除;`src/components/common` 里 4 条断言已退役 `pixel-modal-shell` 的用例同样留在不收集状态,不修断言也不复活旧行为。 +- 边界:只动测试收集范围与两份过期文档的验收命令;不修改任何产品代码、不删除任何测试文件、不改 CI 任务划分(`test:ci:frontend` 仍继承根 include)。 +- 验证:`npm test`(416 文件 / 4391 通过 / 26 跳过,补 include 前是 407 / 4347 / 26)、`npm test -- src/services/sseStream.test.ts`(3 通过,补前是 exit 1)、`npm run ai-game-creator-shell:check:web`(185 文件 / 1808 通过)、`npm run check:doc-index`、`npm run check:encoding`、`git diff --check`。 + +## 2026-09-24 Provider 配置 Debug 脱敏收口(P2 待办关闭) + +- 背景:`AppConfig` / `AppState` / `SpacetimeClientConfig` 早已改成允许清单摘要,但 9 个 provider 配置类型仍直接 `derive(Debug)`,被单独格式化时会打印 URL 内嵌凭据、api_key、AccessKey、私钥 PEM 与私钥路径(当时的 P2 待办已随本条决策关闭并删除)。 +- 决策:这 9 个类型全部改为手写脱敏 `Debug`,口径与 `AppConfig` 一致——只输出枚举、数值、布尔、有界标识(bucket / provider / app_id / mch_id / 证书序列号 / 资源 id)与 `` 占位;凭据、私钥、私钥路径、WS / SSE / HTTP 地址一律不递归格式化。覆盖 `LlmConfig`(platform-llm)、`OssConfig`(platform-oss)、`WechatPayConfig` 与 `WechatConfig`(platform-wechat)、`MattingConfig`(platform-matting)、`VolcengineSpeechConfig`(platform-speech)、`Hyper3dSettings`(platform-hyper3d)、`VectorEngineImageSettings`(platform-image)、`VectorEngineAudioSettings`(platform-audio)。 +- 边界:不改配置字段、构造函数、序列化契约或调用方;只替换 `Debug` 实现并新增哨兵用例。 +- 验证:8 个 crate 全量 `cargo test -p platform-audio -p platform-image -p platform-hyper3d -p platform-matting -p platform-speech -p platform-wechat -p platform-oss -p platform-llm` 全绿;9 条新用例(哨兵值不得出现在格式化结果里,同时保留有界标识)通过;对应 crate 的 `cargo fmt --check`、`npm run check:encoding`、`git diff --check` 通过。 +- 关联:`docs/project-memory/shared-memory/team-conventions.md` 的日志条目已写入「provider 配置必须手写脱敏 Debug 并各带哨兵用例」规则;原待办文件按约定删除,结论以本节与团队约定为准。 + +## 2026-09-24 生成绑定进入门禁 + kind 扫描清单关闭 + +- 背景:`GameCreationAppAssetKind` 的唯一真源在 `shared-contracts` 的声明表,TS union 由 ts-rs 生成到 `packages/shared/src/contracts/generated/`。此前没有任何门禁验证「Rust 改了、生成文件没重新跑」这类漂移,kind 枚举化扫描清单的最后一个未决项就是它(该清单已随本次收口删除)。 +- 决策:新增 `scripts/check-generated-bindings.mjs`:重跑一次 `cargo test --locked -p shared-contracts --features ts-bindings export_bindings`,把生成目录的前后快照逐字节比较,任何新增/变化/删除都以非零退出并提示重生成命令。该检查接入 `npm run lint` 与 `npm run ai-game-creator-shell:check:rust:crates`(CI 的 `agc-rust-crates` job)。 +- 决策:kind 枚举化扫描清单收口并删除——M0 审计的每条未决项都已落到代码或门禁上:旧值只作为显式转换输入或协议标识(`"art-spritesheet" => IconSpritesheet`、`"game-background" => Scene`;`art-spritesheet-slice` / `ui-prototype` / `character-art` / `illustration` / `game-art` 在 `src-tauri/src` 内 0 命中)、非 canonical 值经 `parse_with_context` + `set_non_canonical_asset_kind_reporter` 留痕(AGC 壳 `main.rs` 接 `app_log!`)、旧手写 kind 表在各包内 0 命中。 +- 验证:`npm run check:generated-bindings` 通过;变异验证(把生成文件里的 `"font"` 改成 `"font-drift"`)以 `内容变化 GameCreationAppAssetKind.ts` 失败,重跑恢复;`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` 通过。 + +## 2026-09-24 引用输入区类名维持 `resource-reference-*`(不改名) + +- 背景:`docs/project-memory/todos/【待办】引用输入区后续收口-2026-09-24.md` 第 2 条曾把「`resource-reference-*` 类名重命名」列为待做的机械提交,理由是「与 `RESOURCE_REFERENCE_OVERLAY_SELECTOR` 同批改名,避免选择器与类名短暂不一致」。 +- 审计:选择器常量正好是 `.resource-reference-picker, .resource-reference-menu`,指向的就是这两个组件渲染的类;其余类名也逐条与归属组件同名(`ResourceReferenceInput` / `ResourceReferencePicker` / `ResourceReferenceChip`)。规模为 80 条规则(`styles.css` 78 + `resourceCanvasChrome.css` 2)、17 个文件、32 处测试断言。 +- 决策:不改名。没有现役调用方、公开契约或样式隔离问题需要靠改名解决,纯改名只增加回归面;等出现新的命名口径时,再与选择器常量、样式表与断言一次性同批改。该条以「接受现状」关闭,其余两条(归一化撞名的候选菜单提示、真机手感验收)仍开放。 diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 2efa4c511..31b325018 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -326,13 +326,20 @@ Direct 工具桥会 canonicalize 项目根,事件中的路径可能带 `\\?\` - **易错点**:① 拆 job / 改 job 名后要确认分支保护里没有残留已不再上报的旧 job 名(本仓库现在不配 required context,只需人工确认 CI 结果,见置顶条目的「分支保护口径」);② 每个 job 只预热自己会构建的 Cargo 依赖,`agent-run:smoke` 因为会 spawn `cargo` 必须与 AGC 壳的依赖预热同 job;③ 本地全量 `npm run check:native-shells` 仍会串行跑完所有分组,用它作为本地完整门禁,不要用单组脚本冒充。 - **关联**:`.gitea/workflows/project-ci.yml`、`scripts/check-native-shells.mjs`、`scripts/project-ci-workflow.test.ts`、`.gitea` 分支保护设置。 +## 2026-09-24 重复 `#[test]` 属性会让 Rust 分片门禁报「同一用例被分到两片」 + +- **现象**:`node apps/ai-game-creator-shell/scripts/run-rust-shell-test-shards.mjs` 编译成功后立刻失败:`shard split selected the same test more than once; the split rule must be disjoint`。单独 `cargo test <该用例名>` 一切正常,`cargo test` 编译也不报错。 +- **原因**:`#[test]` 被写了两次——`apps/ai-game-creator-shell/src-tauri/src/workspace_preferences.rs` 的 `client_server_selection_is_normalized_and_validated`。Rust 允许重复 `#[test]`,同一个测试二进制里会把同一个名字注册两次;` --list` 因此列出两条同名条目,分片器的「片并集等于全集且互不重复」自检直接判失败。CI 的每个 Rust shard job 都会跑这条自检,所以这不是本地专属问题。 +- **处理**:删掉多余的那一个 `#[test]`。排查方式:同一文件里连续两行都是 `#[test]`(或 `#[tokio::test]`);全仓扫过,当时只有这一处。 +- **验证**:修复后分片器输出 `2936 tests, 4 shard(s)`、四片各 734 条且不再报 disjoint;`cargo test workspace_preferences:: -- --test-threads=1` 通过。 +- **同一类限制(未改)**:Windows 上分片 runner 走到真正执行时会 `spawn ENAMETOOLONG`(734 个用例名拼成的 argv 超过 Windows 命令行长上限);直接运行测试二进制 `--test-threads=1` 在本机跑到约 20 分钟后长时间无进展(无子进程、CPU 不再增长)。完整 AGC Rust 套件仍以 Linux CI 的分片 job 为准,本地跑定向 filter。 ## 2026-09-14 `check:native-shells` 的调用链扫描在 Windows 上恒假 - **现象**:Windows 本机运行 `npm run check:native-shells:contract` 时,`production-shell-dev-scaffold-scan` 报 `H5 HostBridge call chain scan is missing required files: src/ActiveApp.tsx, ...`,而仓库里这些文件都存在,Linux CI 从不报。 - **原因**:`collectFiles` 在 Windows 上返回 `src\ActiveApp.tsx`,调用链扫描把该路径原样放进 `scannedFiles`,再与 POSIX 写法的期望清单(`h5HostBridgeRequiredCallChainFiles` 的 `src/ActiveApp.tsx`)比较,成员判断恒假。注意 `normalizeModulePath` 不能直接复用:它还会去掉 `.ts/.tsx` 后缀。 - **处理**:新增 `normalizeScannedFilePath`(只统一分隔符、保留后缀)用于 `scannedFiles` 的登记;Linux 上 `split('/').join('/')` 是恒等变换,行为不变。 - **验证**:`node scripts/check-native-shells.mjs --groups=contract` 在 Windows 上 0.6 秒通过(修复前同一条命令必红)。 -- **同一类限制(未改)**:Windows 本机跑 `shells` / `agc-web` / `agc-rust-shard-*` / `agc-rust-smoke` / `release` 这些**带步骤**的分组会在第一条 npm 步骤直接失败:`spawnSync npm.cmd EINVAL`(Node 24 起不能不带 shell 直接执行 `.cmd`;而根 `npm run test` 另有 chmod/0600 语义的 Windows 专属失败)。因此 Windows 本机可用的只有 `--groups=contract`,完整门禁交给 Linux CI;不要为此把 `spawnSync` 改成 `shell: true`(步骤参数里含空格与中文字符串,会被 shell 重新解析)。 +- **同一类限制(未改)**:Windows 本机跑 `shells` / `agc-web` / `agc-rust-shard-*` / `agc-rust-smoke` / `release` 这些**带步骤**的分组会在第一条 npm 步骤直接失败:`spawnSync npm.cmd EINVAL`(Node 24 起不能不带 shell 直接执行 `.cmd`;而根 `npm run test` 另有 chmod/0600 语义的 Windows 专属失败)。因此 Windows 本机可用的只有 `--groups=contract`,完整门禁交给 Linux CI;2026-09-24 补充:`apps/ai-game-creator-shell/scripts/run-rust-shell-test-shards.mjs` 已能在 Windows 上跑起来——它把一片的用例名按 12 KiB 上限切块、复用同一 TMPDIR 逐块运行同一二进制(Linux 上短 argv 仍是单次运行),绕开 `spawn ENAMETOOLONG`。但本机跑 AGC Rust 全量仍然**不实用**:该 crate 每次 `cargo test --no-run` 都会重新链接(并行跑多个 runner 进程会撞 `link.exe exit code 1104`,即输出文件被占用),而且不少用例在本机是纯 CPU 忙等——单次 `background_agent_runtime` 过滤(26 条)就烧掉 35 分钟以上 CPU,其中单条用例单独跑 3.7 秒通过。结论:本机只跑定向 filter;完整口径以 Linux CI 的分片 job 为准,不要为了跑全量把多个 runner 进程并行起来。不要为此把 `spawnSync` 改成 `shell: true`(步骤参数里含空格与中文字符串,会被 shell 重新解析)。这条约束只针对该步骤 runner:`apps/mobile-shell/scripts/check-expo-config.mjs`、`check-eas-build-config.mjs`、`check-expo-export.mjs` 三处 2026-09-24 已改成「固定命令串 + `shell: true`」——它们的 argv 全由字面量拼成(无空格/中文),既避开 `npm.cmd EINVAL`,也避开 Node 对「shell + args 数组」的 DEP0190 警告。另一类 Windows 专属缺陷是「把 `new URL(...).pathname` 当文件系统路径用」:`apps/desktop-shell/scripts/stage-release-binary.mjs` 原本写 `path.resolve(new URL('../../../', import.meta.url).pathname)`,Windows 下 pathname 是 `/F:/…`,resolve 后拼成 `F:\F:\Projects\…`,于是 release 分组的 `desktop-shell:stage-release-binary` 必然报「desktop release binary is missing」;2026-09-24 改成 `fileURLToPath(new URL(...))` 后本机通过(产物落在 `build/native/desktop/`,该目录已被忽略规则覆盖)。同类写法还剩两处且**不需要改**:`apps/mobile-shell/scripts/check-config.mjs` 用它比较两侧都是 URL pathname 的相对路径(口径一致),`apps/ai-game-creator-shell/scripts/check-macos-bundle.mjs` 只在 macOS 上运行。同类限制还有 `npm run check:pingora-gateway-smoke`:它在第一步用 `openssl req` 生成自签证书,而本机 PATH 上是 Strawberry 的 `C:\Strawberry\c\bin\openssl.exe`,其编译期默认 config(`Z:/extlib/_5040__/ssl/openssl.cnf`)不存在,于是整条失败。2026-09-24 的处理:① 本机跑之前设 `OPENSSL_CONF=C:\Program Files\Git\usr\ssl\openssl.cnf`(该文件存在,OpenSSL 3.x 可读);② 脚本自身两处平台/竞态问题已修——`resolveGatewayBinary()` 在 Windows 找 `pingora-gateway.exe`,「API 并发保护」用例改成先把被放行的响应读完再关客户端连接(原先释放 hold 后立刻 FIN,在 Windows 上稳定报 `HTTP 响应提前关闭`)。修完本机该门禁 `通过`。同一类限制下 `npm run check:database-backup` 在 Windows 本机也会失败——它从 `scripts/database-backup-to-oss.mjs` 取空间预检路径,内部直接调用 `du`;该门禁面向 Linux 生产机,本地以 Linux CI 或生产机结果为准。还有一批**面向 Linux 生产机/CI** 的部署门禁,在 Windows 本机不跑:`check:production-api-release`(内层 `scripts/build-production-release.sh` 用 `bash`/`chmod`,本机报「缺少命令: node」)、`check:production-api-deploy`(依赖 `/usr/bin/chmod` 与 `/usr/bin/stat`)、`check:production-health-patrol`(巡检项直接调 `systemctl`,本机是 `spawn systemctl ENOENT`)、`check:pingora-release-readiness`(步骤命令写死 `npm`,本机 `spawn npm ENOENT`,且它的清单本身就含上面这些 Linux-only 项)、`check:pingora-tls-cert-sync`(按 Linux 文件模式与拷贝语义做临时目录对账)。2026-09-24 把剩下的 pingora 切换/审计类门禁也跑了一遍,结论同样是 Linux-only:`check:pingora-realpath-canary-toggle`(临时目录按 Linux 拷贝语义构造,本机 ENOENT)、`check:pingora-direct-rollback` / `check:pingora-direct-enable` / `check:pingora-release-readiness-plan` / `check:pingora-direct-rehearsal-status` / `check:pingora-cutover-status-snapshot`(断言 `/opt/genarrative/current/scripts/deploy/*` 的脚本身份、`systemctl show ExecStart`、公网端口归属漂移、systemd env 漂移等 shell/systemd 行为)、`check:pingora-health-patrol-env-switch`(断言临时 env 文件 mode 0600,本机是 666)、`check:pingora-current-release-audit`(走同一批部署脚本)。反过来,2026-09-24 在本机实跑**通过**的运维类门禁有:`check:pingora-direct-preflight`、`check:pingora-canary-live-guard`、`check:pingora-direct-live-guard`、`check:nginx-pingora-canary`、`check:pingora-canary-access-log-parity`、`check:pingora-gateway-env-shadow-switch`、`check:pingora-canary-docker`,以及设置 `OPENSSL_CONF` 后的 `check:pingora-gateway-smoke`。 - **关联**:`scripts/check-native-shells.mjs` 的 `collectH5HostBridgeCallChainFiles` / `normalizeScannedFilePath`。 ## 2026-09-14 项目写锁的同进程复用判据不能只看 pid @@ -448,8 +455,9 @@ AGC 的 Cocos 能力来自随客户端分发的 `agc-cocos-editor` 内置插件 首页命名回合成功后创建命令失败且不会留下项目目录。用户通过目录选择器创建的 项目仍走 user-selected 权限范围。 -- 2026-09-17 补充:首页与模板建项支持用户自选 `projectsRoot`(见 - `docs/project-memory/plans/【实施计划】AGC项目创建目录可选-2026-09-17.md`)。 +- 2026-09-17 补充(2026-09-23 修订机制):首页与模板建项使用用户自选的项目创建目录。 + 该偏好现由 Rust 客户端偏好 `workspace-preferences.json` 持有并带变更事件;建项命令不再从 + 渲染层接收 `projectsRoot`,由 Rust 读回偏好后执行同一套门禁。 自选目录只有一条合法来源——本机原生目录选择器返回的目录,并且必须在 Rust 侧 通过 `validate_requested_game_project_creation_root` (绝对路径 / 无控制字符 / 已存在普通目录 / 非链接与 reparse point / @@ -5413,6 +5421,7 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` 1. **相对路径**:该模块全部经 `src/services/apiClient.ts` 的 `requestJson` / `fetchWithApiAuth` 发请求,最终落到**裸 `window.fetch('/api/...')`**(相对路径 + `credentials: 'same-origin'`)。AGC 打包态页面来自 Tauri asset 协议(`frontendDist: ../dist`),相对 `/api/...` 打到 asset 协议自身,永远到不了 api-server。 2. **CSP**:`apps/ai-game-creator-shell/src-tauri/tauri.conf.json` 的 `connect-src` 只放行 `'self'`、`https://agc-dev.oss-rg-china-mainland.aliyuncs.com`、`http://127.0.0.1:*`、`ws://127.0.0.1:*`(`devCsp` 同口径)。`https://dev.genarrative.world` 与 `https://www.genarrative.world` **都不在名单里**——即便改成绝对地址也会被 WebView 拒掉。 - 处理(结论):AGC 访问平台接口**只能**经 `apps/ai-game-creator-shell/src/services/clientHttp.ts::fetchClientHttp`——它把相对路径解析成当前选定服务器的绝对地址,并改走 `@tauri-apps/plugin-http`(Rust 侧发请求,不受 WebView CSP 约束)。因此平台接口在 AGC 侧都要在 `src/services/clientApi.ts` / `src/services/clientAuth.ts` 里包一层宿主实现,例如 `loadEditorAssetLibrary()` 就是同一个 `/api/editor/assets/library` 端点另写的一份。 +- 更正(2026-09-24):AGC 渲染层已经不再持有任何 HTTP 通道。平台接口、OSS 素材直传、Provider、错误上报与账户/认证的网络 IO 全部下沉 Rust(`src-tauri/src/account_api.rs`、`auth_session.rs`、`platform_asset_upload.rs`、`game_distribution_publish.rs`、`error_report/submit.rs`),`clientHttp.ts::fetchClientHttp` 与 Tauri HTTP 插件通道已删除,`capabilities/main.json` 也不再授予 `http:default`。上面「只能经 fetchClientHttp」的结论只描述 2026-09-24 之前的实现。 - **判据陷阱**:`npm run dev` 下 AGC 的 vite 配了 `/api` 代理(`apps/ai-game-creator-shell/vite.config.ts` 的 `server.proxy`),那些裸 `fetch('/api/...')` 在 dev 里**看起来能跑**。判断一个网页端模块能不能被 AGC 复用,必须按打包态(asset 协议 + CSP)推演,不能拿 dev 的现象当证据。 - 关联:`src/services/image-editor/editorProjectClient.ts`、`src/services/apiClient.ts`、`apps/ai-game-creator-shell/src/services/clientHttp.ts`、`apps/ai-game-creator-shell/src-tauri/tauri.conf.json`、`apps/ai-game-creator-shell/vite.config.ts`。 @@ -5639,7 +5648,7 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - **现象**:同一天两次 Repository checks 红,都不是代码写错,而是「本地只跑了门禁的一个子集」:① `dd7cf401a` 给 lint-staged 加了 `*.rs` 键,**本地从未跑过 `check:git-hooks`**(它是 `npm run lint` 链里的一环),而 `scripts/git-hooks.test.mjs` 用 `assert.deepEqual` 钉住 lint-staged 的**整份配置形状** → CI 以 `deepStrictEqual` 失败;② 本批更早还因 `check:rustfmt` 红过一次(`15660a98b` 修掉 8 处格式偏差),成因是 pre-commit 的 lint-staged 当时只覆盖 `*.{js,mjs,cjs,ts,tsx}`,Rust 格式在本地没有任何守卫。 - **原因**:`npm run lint` 是一条 `&&` 长链 —— `check:encoding && check:npm-workspaces && check:git-hooks && check:rustfmt && check:spacetime-schema && check:production-ops && check:preview-deployer && check:maintenance-page && lint:eslint && typecheck`(其中 `check:git-hooks` = `node --test scripts/git-hooks.test.mjs`)。**只要中间某一步失败,它之后的步骤根本不会执行**,于是「跑到第 N 步就以为本地绿了」;而 CI 的 Repository checks 跑的是 `scripts/check-repository-ci.sh` → `SPACETIME_SCHEMA_BASE_REF=… npm run lint`(外加 `appSurface.test.ts`、`npm run build`、基线到候选提交的 `git diff --check`)。更隐蔽的是:本地若因**环境原因**在中间断掉(如 Windows 上 `check:git-hooks` 第 2 个用例的 EBUSY),**后面那些本来能通过的步骤也从未被验证过**。③ 还有一类同样隐蔽的是**同一条命令的口径差异**:CI 的 `git diff --check` 跑的是**提交范围** `git diff --check "${base_ref}"..."${head_ref}"`(base 取 PR 的 base sha,CI 日志里是 `[repository-ci] base=…`),而本地裸跑 `git diff --check`(工作树 vs 索引)在干净树上**恒为空**——于是「本地 `git diff --check` 干净、exit 0」根本不能证明 CI 这一跳会过:`pitfalls.md` 末尾多出的那一个空行(`f16aa440b`)就是这样漏掉的,而且它在前两次推送里都因为链条分别停在 `check:git-hooks` / `check:rustfmt` 而从未被这一跳检查过。本地要同口径复现与自检,必须用 `git diff --check ..HEAD`,不要裸跑 `git diff --check`。 - **处理**:push 前按链路逐条跑,不要只跑子集;`&&` 链在某一步失败时,**必须把失败步之后的每一步单独再跑一遍**(上列 10 步 + `git diff --check`),逐条记 exit code(取 exit code 不要接管道)。凡改动碰到 `package.json` / `.husky/` / `scripts/` 下的门禁资产,**`check:git-hooks` 是必跑项**——它钉住 hook 与 lint-staged 配置的形状,增删键都会让它以 `deepStrictEqual` 失败。 -- **验证**:本次 `check:git-hooks` 因本机 Windows EBUSY 中断后,把其后各步单独跑齐:`check:spacetime-schema` / `check:production-ops` / `check:preview-deployer` / `check:maintenance-page` / `lint:eslint` / `typecheck` / `check:encoding` 全部 `exit 0` —— 即「因为前一步红而没跑到」的部分本来是全绿的;只有 `check:rustfmt` 红,且红在别人在途的 `.rs`(`assets.rs:519` 落在其未提交 hunk `+470,62`、`commands.rs:3079` 落在其未提交 hunk `+3068,58`)。变异验证:把 `*.rs` 从 `package.json` 摘掉 → `check:git-hooks` 第 1 个用例以同样的 `deepStrictEqual` operator 变红(`# fail 2`);还原(`package.json` SHA256 与改前一致)后该用例回 `ok`。 +- **验证**:本次 `check:git-hooks` 因本机 Windows EBUSY 中断后,把其后各步单独跑齐:`check:spacetime-schema` / `check:production-ops` / `check:preview-deployer` / `check:maintenance-page` / `lint:eslint` / `typecheck` / `check:encoding` 全部 `exit 0` —— 即「因为前一步红而没跑到」的部分本来是全绿的;只有 `check:rustfmt` 红,且红在别人在途的 `.rs`(`assets.rs:519` 落在其未提交 hunk `+470,62`、`commands.rs:3079` 落在其未提交 hunk `+3068,58`)。变异验证:把 `*.rs` 从 `package.json` 摘掉 → `check:git-hooks` 第 1 个用例以同样的 `deepStrictEqual` operator 变红(`# fail 2`);还原(`package.json` SHA256 与改前一致)后该用例回 `ok`。2026-09-24 独立复核:按同一做法摘掉 `*.rs` 后第 1 个用例同样以 `deepStrictEqual` 变红(这次运行汇总为 `# pass 1 / # fail 1`,与当时 `# fail 2` 的差异来自该文件后续用例是否继续执行),还原后 SHA256 逐字节一致、`check:git-hooks` exit 0。 - **关联**:`package.json` 的 `lint` / `check:git-hooks` / `check:rustfmt`、`scripts/check-repository-ci.sh`、`scripts/git-hooks.test.mjs`、`.husky/pre-commit`、提交 `dd7cf401a` / `2a7bfadd7` / `15660a98b`。 ## 2026-09-12 「矩形从哪来」缺一路输入时,别让它静默回落到世界原点:7 条栏目标题栏在空项目里叠成一摞 @@ -5734,7 +5743,7 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - **原因**:`3c7b02b9f`(2026-09-15)为了让 content 通过 Rust 的「空 `input_text`」校验,在投影层加了 `appendInputText`(`if (text.trim())` 才落 part,并与相邻文本合并)。root 子节点之间补的段落分隔符与 `LineBreakNode` 传进来的都是 `'\n'`,`trim()` 为空 ⇒ 整段丢掉;chip 后那一段文字随后另起一个 part,派生文本用 `''` 直接拼接,于是粘成 `@hero把这一版改成夜景`。`41366dd71` 又把消息正文 / 队列 chip / 快速编辑的文本派生切到这条投影上,缺陷扩散到界面与出站 prompt。 - **处理(最终口径)**:不保留任何前端过滤,而是去掉规则和它的成因——Rust `validate_direct_codex_user_item` 改成只判整条 content(`content_has_meaningful_input`:有一段非空白文本或任意非文本 part 即有效),单个纯空白 `input_text` 合法;`ResourceReferenceInput` 的投影原样透传编辑器节点,既不丢空白也不与相邻 part 合并。中间版本(把待写文本「向前合并」到下一个 part)已随之删除:它仍会丢掉尾随换行与「两个 chip 之间只隔一个换行」的分隔,也仍要让前端替用户改写内容。 - **验证**:Rust `validation.rs` / `wire.rs` 新增「单个纯空白 part 通过校验、整条全空白拒绝」用例;`apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx`「引用后面的段落分隔原样落进 content」断言 `[ref, { type: 'input_text', text: '\n' }, { type: 'input_text', text: '…' }]` 与派生文本逐字一致;`tests/appSurface/project-development.suite.ts` 的 Godot 用例断言 Shift+Enter 的两个换行各自成 part。 -- **关联**:`apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx`(`collectDraftParts`)、`apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/validation.rs`、`docs/project-memory/plans/【里程碑】DirectProject canonical content严格边界-2026-09-16.md`。 +- **关联**:`apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx`(`collectDraftParts`)、`apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/validation.rs`、`docs/【功能说明】AGC聊天素材引用-2026-09-08.md`(原开发期里程碑已于 2026-09-24 验收归档并删除,canonical content 口径以该功能说明为准)。 ## 2026-09-16 派生文本漏传 `manifest.assets`:`@引用` 从显示名退化成内部 id @@ -5761,6 +5770,12 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - **排障注意**:Release GUI 没有 panic hook、也没有 stderr,panic 文案不会落盘;`diagnostics/application.log` 只会停在崩溃前最后一行(本次停在 `agent.codex_app_server.remote_control disabled` 之后),所以「应用日志没有异常」不能当作「没有 Rust panic」,要结合 WER 事件、minidump 的 fail-fast 参数与调用线程上下文判断。 - **关联**:`apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs`、`apps/ai-game-creator-shell/src-tauri/src/main.rs`(`install_agent_runtime_async_runtime_with_deep_stack`)、`apps/ai-game-creator-shell/src-tauri/src/commands.rs`(`cancel_direct_codex_turn`)。 +## 2026-09-24 Windows 本机跑 server-rs 全量 workspace:两类已知失败,其余全绿 + +- **命令与结果**(2026-09-24 实跑,镜像 CI):`cargo test --locked --workspace --exclude spacetime-module --no-fail-fast --manifest-path server-rs/Cargo.toml` → 2 个 target 失败,其余 crate 全绿:`api-server --bin api-server` **1124 passed / 11 failed / 8 ignored**,`server-manager-panel --lib` **5 passed / 1 failed**。 +- **一、`api-server::wallet_refund_outbox::tests` 全部 11 条本机失败**:panic 是 `Io(Os { code: 5, kind: PermissionDenied })`,来自 outbox 用 `fs::hard_link` 在 `%TEMP%` 下做原子发布(`wallet_refund_outbox.rs` 201/449/468 行)。这是本机环境的既有基线——decision-log 多条验证记录早就写着「`wallet_refund_outbox` 本机环境失败,与基线一致」(当时是 3 条,模块长到 12 条测试后失败数同步变大)。不要为了让它变绿改断言或放宽发布语义;生产与 CI 在 Linux 上跑。 +- **二、`server-manager-panel::fonts::tests::finds_existing_system_cjk_font` 失败**:`find_cjk_font_candidate()` 依赖 fontconfig 的 `fc-match`,Windows 本机没有该命令,因此断言「本机至少有一个 CJK 字体」必红。这是 Linux 专属用例,同样不要改成「找不到也算过」。 +- **口径**:server-rs 的完整测试口径以 Linux(CI 的 `Server-rs tests` job)为准;本机跑全量时只把上面两类失败视为环境噪声,其余任何失败都要当真实信号处理。 ## 2026-09-16 AGC 壳跑过 `cargo test` 后前端 typecheck 必红:ts-rs 导出把 `generated/*.ts` 重写成另一种形状 - **现象**:在 `apps/ai-game-creator-shell/src-tauri` 跑过 `cargo test` 之后,`npm run ai-game-creator-shell:typecheck` 报 10 条类型错(`src/features/project-workspace/resourceReferences.ts:106-112` 的 `string | undefined` 不能赋给 `string | null`;同文件 134 行的对象字面量带 `type: 'message'`,而 `DirectCodexUserMessageItem` 里没有该字段),`npm run ai-game-creator-shell:build` 也死在 `beforeBuildCommand` 的同一条 typecheck 上。 @@ -5768,6 +5783,7 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - **处理(现行口径)**:不要把重写结果当改动提交。跑过 `cargo test` 或构建后只恢复 `apps/ai-game-creator-shell/src/view/project-development/chat/generated/DirectCodexUser*.ts` 的仓库版本,再删掉多出来的 `DirectCodexUserMessageEnvelope.ts`;不要恢复整个 `generated/` 目录,以免误删 DirectThread 的现役绑定。绑定与前端形状冲突时以**已提交的 DirectCodexUser 绑定 + 前端**为基准排查。 - **验证**:恢复仓库版本后 `npm run ai-game-creator-shell:typecheck` exit 0(`[skill-pack] OK`);保留重写结果时同一条命令 exit 2。release 构建本身还会在 `src/features/ui-editor/types/` 落下 `BindingChange.ts` / `BindingDTO.ts` 两个无人引用的生成产物;它们不属于前端契约,发现后直接删除,不提交。 - **关联**:`apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/`(ts-rs 导出源)、`apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts`、`apps/ai-game-creator-shell/scripts/build-release.mjs`(`beforeBuildCommand`)。 +- **2026-09-24 补充(纯格式 churn 的一档)**:直接运行 AGC 的测试二进制(含全量套件,里面带 `export_bindings`)同样会把 `src/view/project-development/chat/generated/DirectThread*.ts` 重写成 raw ts-rs 形态——双引号、行尾空格、`};` 变 `, };`——于是 `git diff --check` 报一片 trailing whitespace,而 `npm run check:generated-bindings`(只覆盖 `packages/shared/src/contracts/generated`)不会报警。处理:对这组文件跑一次 `npx prettier --write "apps/ai-game-creator-shell/src/view/project-development/chat/generated/*.ts"` 做归一化,再确认 `git diff --stat` 为空——为空就说明这一档只是格式 churn,没有语义变化;不要为它盲目 `git checkout` 整个目录。该目录目前没有自动漂移门禁,靠「跑完测试后归一化 + diff 检查」把关。 ## 2026-09-16 Node 26 下 vitest 的 jsdom 用例拿不到 window.localStorage @@ -5846,9 +5862,9 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - **现象**:DirectProject 输入盒里粘贴(或连续输入)长文本,提交时 `chat_with_game_creator_direct_codex` 根本没发出去,界面停在空输入盒;`chat-composer` 用例里表现为「队列/终止/语音追加」五条一起红,但手工操作只在快速输入后偶发。 - **原因**:`ResourceReferenceInput` 的受控回写写在 `useEffect` 里,判据是「`value`/`references` 与编辑器当前草稿不一致就重建 root」。宿主对草稿的回显(`chatInput`/`chatReferences`)永远晚于编辑器的 Lexical 提交:一次渲染提交后它的被动 effect 可能排在用户下一次输入之后才执行,于是它读到的是**旧 `value` 加新编辑器状态**,判定不一致→`applyDraftToRoot` 整份重建→编辑器 `onChange` 把空草稿写回宿主→宿主再回显空值,来回清空。`references` 每次 `handleComposerDraft` 都换数组身份,进一步保证这段 effect 每次都跑。 -- **处理**:受控回写改成 `useLayoutEffect`,与本次提交同帧执行,读到的 props 与编辑器状态属于同一次提交;被动 effect 的滞后回调不再可能出现。旧 `value`+`references` 双轨语义本身仍是待收口的债务(见 canonical content 里程碑)。 +- **处理**:受控回写改成 `useLayoutEffect`,与本次提交同帧执行,读到的 props 与编辑器状态属于同一次提交;被动 effect 的滞后回调不再可能出现。当时的 `value`+`references` 双轨语义已在 2026-09-21 的 composer canonical content 闭环里收口:`ResourceReferenceInput` 现在只接 `initialContent` 与 `onChange(draft: ChatComposerDraft)`,`ChatComposerDraft` 只剩 `content` 一个字段,旧文本 + 引用重建 root 的回写路径已删除(`docs/【功能说明】AGC聊天素材引用-2026-09-08.md`)。 - **验证**:`apps/ai-game-creator-shell/tests/appSurface/chat-composer.suite.ts` 的队列、终止×2、恢复回合、语音追加五条用例转绿;`tests/resourceReferenceInput.test.tsx` 全绿。 -- **关联**:`apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx`、`docs/project-memory/plans/【里程碑】DirectProject composer canonical content闭环-2026-09-21.md`。 +- **关联**:`apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx`、`docs/【功能说明】AGC聊天素材引用-2026-09-08.md`(该闭环里程碑已于 2026-09-24 验收归档并删除)。 ## 2026-09-21 删链路只删订阅、没删它喂的 state:留下恒为默认值的死 prop @@ -5944,6 +5960,13 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - **现象**:dev 渠道 0.1.129 安装包启动后,窗口顶部同时出现系统标题栏(浅蓝条 + 原生最小化/最大化/关闭)与前端自绘 `WindowChrome`;窗口缩到 816x639(约 800x600 客户区);登录页常驻「无法连接登录服务,请确认配套后端或 API 代理已启动后重试」。应用日志同一秒出现 `startup.window-title.failed: 缺少 client 主窗口`,而 `https://dev.genarrative.world` 在浏览器/curl 下可正常响应。 - **原因**:`ebb288a6a`(2026-09-23 18:49)为统一渠道产品名,在渠道配置里加了 `app: { windows: [{ title: productName }] }`。Tauri 的 `--config` 合并是 JSON Merge Patch(`tauri-utils/build.rs` 用 `json_patch::merge`):对象递归合并、**数组整体替换**。基线窗口数组被整条换掉后,`label` 回落到默认 `main`(不是 `client`)、`decorations` 回落到 `true`、尺寸回落到 800x600。三条症状同源:① `decorations: true` → 系统标题栏;② 尺寸回落 → 816x639;③ label 不再是 `client` → `capabilities/main.json`(`windows: ["client"]`,承载 `http:default` 与平台 API scope、dialog/opener/updater/剪贴板权限)整条不命中,前端 `fetchClientHttp` 走 `@tauri-apps/plugin-http` 时被 ACL 拒绝并抛错,登录状态检查就报成"连不上服务器"。判断关键:**这类"连不上服务"是权限拒绝,不是网络故障——先看窗口 label 与 capability 的 `windows` 是否还对得上,别去查后端与代理**。 +- 更正(2026-09-24):症状链里的渲染层 HTTP 部分已随网络通道退役而消失——`capabilities/main.json` 不再承载 `http:default`,渲染层也没有 `fetchClientHttp` / `@tauri-apps/plugin-http`,登录请求由 Rust 发出、不受这条 ACL 约束。但「capability 按窗口 label 绑定」仍是判据,只是现在影响的是剪贴板、原生对话框、opener 与 updater 权限。 - **处理(现行口径)**:`createChannelConfig()` 从基线 `src-tauri/tauri.conf.json` 读完整 client 窗口对象后展开、只覆盖 `title`(`readBaseClientWindow()`),渠道配置不得再出现"只写 `title`"的窗口对象。新增守卫:`build-release.test.mjs` 用同语义的 merge patch 复现 Tauri 合并并断言 `label=client` / `decorations=false` / 1280x800 / min 1280x720 且承载 `http:default` 的 capability 必须包含该 label;`check-config.mjs` 增补基线 `decorations !== false` 失败关闭。 - **验证**:`node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs scripts/cargo-features.test.mjs scripts/release-oss.test.mjs scripts/prepare-macos-codex.test.mjs`(60/60)、`node apps/ai-game-creator-shell/scripts/check-config.mjs` 通过;`createChannelConfig('dev', …)` 实测输出含 `label: client` 与 `decorations: false`。修复后的安装包尚未重新构建与安装,真机观感与登录链未复核。 - **关联**:`apps/ai-game-creator-shell/scripts/build-release.mjs`、`apps/ai-game-creator-shell/scripts/build-release.test.mjs`、`apps/ai-game-creator-shell/scripts/check-config.mjs`、`apps/ai-game-creator-shell/src-tauri/capabilities/main.json`、`docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md`。 + +## 2026-09-24 根 vitest 白名单漏掉现役模块测试:文档里的验收命令变成 "No test files found" + +- **现象**:`npm test -- src/services/sseStream.test.ts`(SSE 传输层收口约定与静态预览 MVP 验收清单里都写着的验收命令)报 `No test files found, exiting with code 1`;同一时期 `apps/ai-game-creator-shell/tests/resourceBatchTagsIntegration.test.tsx`、`resourceTagStatsRefresh.test.tsx` 在 `--root apps/ai-game-creator-shell` 口径下整文件以 `ReferenceError: describe is not defined` 失败、0 个用例执行。 +- **原因**:`e9c3dc112 退役旧创作模板业务`(2026-07-17)把根 `vitest.config.ts` 的 `src/**/*.test.ts(x)` 通配收成显式白名单,只列了「当时确认存活」的目录;`src/services/sseStream.test.ts`、`src/services/frontendRuntimeConfigService.test.ts`、`src/persistence/**`、`src/routing/RouteImageReadyGate.test.ts`、`src/editor/shared/jsonClient.test.ts`、`src/components/platform-entry/PlatformProfilePrimitives.test.tsx`、`packages/shared/src/theme.test.ts`、AGC 的 `tf2css.test.tsx` 这些**现役**模块的用例被一起漏掉(用临时配置收进来跑:261 个文件全绿)。同时 194 个 AGC 测试文件里有 2 个只依赖 `describe/it` 全局、没有显式导入,换执行口径就整文件不收集。 +- **处理**:把上面这些现役用例补回 `vitest.config.ts` 的 include(不恢复 `src/**` 通配,避免把旧创作链路的退役测试一起收回来);那两个 AGC 文件按同目录套件惯例从 `./appSurface/harness` 显式导入 `describe` / `it`;同步修订两份文档里指向已删除模块的验收命令。 diff --git a/docs/project-memory/shared-memory/team-conventions.md b/docs/project-memory/shared-memory/team-conventions.md index 2b69a5c0f..7d5bfd8cd 100644 --- a/docs/project-memory/shared-memory/team-conventions.md +++ b/docs/project-memory/shared-memory/team-conventions.md @@ -49,10 +49,11 @@ - AGC 当前 Agent 与策划 Agent 的消息层级共用 `packages/shared` 的 `AgentMessageContent`:正文使用 `body`,思考、中间输出与工具调用使用 `process`;过程字号和颜色由共享组件统一定义,错误状态保留语义色。 - 后端遵循 `module-*`、`spacetime-module`、`spacetime-client`、`api-server`、`platform-*`、`shared-contracts` 的现役边界。 - 前端只负责表现、交互和临时 UI 状态;正式状态来自后端投影、API 或持久化契约。 +- AGC 渲染层是离线前端:平台接口、OSS 素材直传、Provider、错误上报与账户/认证的网络 IO 全部在 Rust 的 reqwest facade,渲染层不得再出现 `fetch(` / `XMLHttpRequest` / `EventSource` / `sendBeacon(` / `new WebSocket(` 或 `@tauri-apps/plugin-http`;客户端窗口 capability 也不得授予 `http:default`。`check:native-shells --groups=contract` 的 `ai-game-creator-shell-user-dev-boundary` 用负向门禁钉住这条,改动渲染层网络边界必须同批改该门禁与 `build-release.test.mjs`。 - 对已明确退役且无现役调用方、公开契约、持久化数据、活跃实例或迁移要求的对象,直接清理实现、专属测试和说明,将权威文档更新为当前状态;历史由 Git 保存。公开契约、持久化数据和正式迁移按实际需求保留最小兼容及对应测试。 - 修改 `/api/external/v1` 时,同批更新 `docs/openapi/genarrative-external-v1.openapi.json` 与契约测试。 - 修改 SpacetimeDB schema 时遵守字段追加/default 约束,同步 migration、表目录、生成绑定,并运行 schema 检查;删除、改名、重排或改类型前先确认迁移计划。 -- 日志不递归输出完整配置、应用状态或 provider client;新增字段默认不进入安全摘要。 +- 日志不递归输出完整配置、应用状态或 provider client;新增字段默认不进入安全摘要。所有 provider 配置类型(`LlmConfig`、`OssConfig`、`WechatConfig`、`WechatPayConfig`、`MattingConfig`、`VolcengineSpeechConfig`、`Hyper3dSettings`、`VectorEngineImageSettings`、`VectorEngineAudioSettings`)都必须手写脱敏 `Debug`:只输出枚举、数值、布尔、有界标识与 `` 占位,凭据、私钥、路径与 URL 一律不递归格式化,并各带一条哨兵值回归用例(`cargo test -p platform-* debug`)。新增同类配置必须照此办理,不允许直接 `derive(Debug)`。 - HTTP 横切能力集中在 Axum/Tower 中间件:正常与降级路由复用追踪层;指标与 trace 使用 `MatchedPath` 模板及固定兜底,不把请求 ID、实际资源 ID 或 query 放入指标标签。在途请求通过 RAII guard 覆盖 Future 取消与 panic unwind;请求执行和响应体存活分别计量,不能把 handler 耗时当作 SSE 全生命周期。 - 业务依赖在组合根显式装配,Axum `FromRef` 只抽取可浅拷贝的窄能力。项目元数据与 External API 鉴权不持有完整 `AppState`,测试经相同接口注入替代依赖。集中鉴权仍保留方法级 fallback、公开入口、MCP 和 body limit 顺序;Provider span 跳过完整参数,不隐藏计费、重试、幂等或事务规则。 - 中文文案、注释和文档保持中文与 UTF-8,优先局部补丁。 diff --git a/docs/project-memory/todos/【已知问题】AppConfig与AppState调试输出敏感配置泄漏-Master遗留-2026-08-07.md b/docs/project-memory/todos/【已知问题】AppConfig与AppState调试输出敏感配置泄漏-Master遗留-2026-08-07.md deleted file mode 100644 index 266b6a453..000000000 --- a/docs/project-memory/todos/【已知问题】AppConfig与AppState调试输出敏感配置泄漏-Master遗留-2026-08-07.md +++ /dev/null @@ -1,29 +0,0 @@ -# Provider 配置 Debug 输出脱敏待办 - -更新时间:`2026-08-25` - -状态:主链已收口,历史 Provider 配置类型的独立 `Debug` 脱敏仍未完成,风险等级 `P2`。 - -## 当前事实 - -- `AppConfig`、`AppState`、`AppStateInner` 和 `SpacetimeClientConfig` 已使用允许清单或摘要输出,主配置链不再递归打印凭据。 -- 哨兵测试 `debug_summaries_redact_all_runtime_credentials` 继续作为主链回归门禁。 -- 以下类型仍直接派生 `Debug`,被单独格式化时可能输出敏感字段: - - `VectorEngineAudioSettings` - - `VectorEngineImageSettings` - - `LlmConfig` - - `OssConfig` - - `WechatPayConfig` - - `WechatConfig` - - `Hyper3dSettings` - - `VolcengineSpeechConfig` - - `MattingConfig` -- 在全部类型完成脱敏前,禁止新增这些配置整对象的日志调用。 - -## 关闭条件 - -1. 上述类型全部改为手写脱敏 `Debug` 或统一的 secret wrapper。 -2. 每个敏感字段都有唯一哨兵值回归测试,证明格式化结果不包含原值。 -3. 运行相关 crate 定向测试、`npm run check:encoding` 和 `git diff --check`。 - -关联:`server-rs/crates/api-server/src/config.rs`、`server-rs/crates/api-server/src/state.rs`、各 `platform-*` crate、`docs/project-memory/shared-memory/team-conventions.md`。 diff --git a/docs/project-memory/todos/【待办】AGC资源kind枚举化扫描清单-2026-09-15.md b/docs/project-memory/todos/【待办】AGC资源kind枚举化扫描清单-2026-09-15.md deleted file mode 100644 index 930525bcc..000000000 --- a/docs/project-memory/todos/【待办】AGC资源kind枚举化扫描清单-2026-09-15.md +++ /dev/null @@ -1,221 +0,0 @@ -# 【待办】AGC 资源 kind 枚举化扫描清单 - -| 字段 | 值 | -| --- | --- | -| 状态 | open | -| 创建日期 | 2026-09-15 | -| 所属主规范 | `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` | -| 关闭条件 | shell 内所有 GameCreationApp 资源 kind 候选均完成语义归类、代码处理决定和验证证据记录 | - -## 扫描规则 - -只扫描 `apps/ai-game-creator-shell`。`server-rs` 只作为 api-server 有效词汇参考,不把 server-side `asset_kind` 纳入本清单迁移。 - -每个命中必须回到上下文并填写:位置、当前值、真实语义、是否进入 manifest、是否生产写入、目标类型、处理动作、验证证据。 - -## 首轮候选分组 - -### 必须审计为 GameCreationAppAssetKind - -- `image` -- `scene` -- `character` -- `character-animation` -- `icon` -- `icon-spritesheet` -- `icon-spec` -- `ui-design` -- `ui-design-doc` -- `publication-material` -- `spec` -- `video` -- `audio` -- `sound-effect` -- `background-music` -- `font` -- `document` -- `code` -- `unknown` - -### 已发现的非 canonical 候选,必须逐处判定 - -- `asset` -- `ui` -- `animation` -- `game-background` -- `character-art` -- `game-art` -- `illustration` -- `art-spritesheet` -- `art-spritesheet-slice` -- `ui-prototype` -- `game-entry` -- `game-script` -- `game-style` - -### 明确暂不纳入本 PR - -- `source.kind` -- `source.generationKind` -- MIME / `mediaType` / 文件扩展名 -- workflow、generation、task、path、tracking、plugin 等其他 kind 字段 - -## 初始文件入口 - -- `src-tauri/src/assets.rs` -- `src-tauri/src/commands.rs` -- `src-tauri/src/project/manifest.rs` -- `src-tauri/src/project/resource_editor.rs` -- `src-tauri/src/ui_editor/` -- `src-tauri/src/agent/direct_runtime.rs` -- `src-tauri/src/agent/direct_tool_bridge.rs` -- `src-tauri/src/agent/generation/` -- `src-tauri/src/agent/runtime_actions/` -- `src/features/project-development/` -- `src/features/project-workspace/` -- `src/features/resource-canvas/` -- `src/features/ui-editor/` - -## 当前未决项 - -- [x] `asset`:确认是上传推断的兜底值,已改为无法判断时写 `Unknown`,不再回落到 `asset`。 -- [x] `art-spritesheet` / `art-spritesheet-slice`:确认是平台请求与图集 workflow 词汇;manifest 写入分别收口为 `IconSpritesheet` / `Icon`,协议标识只留在各自字符串字段。 -- [x] `game-background` / `game-art` / `illustration` / `character-art`:确认只出现在平台请求词汇;写入 manifest 前经显式转换函数收口为 `scene` / `image` / `character`。 -- [x] `ui` / `ui-prototype`:确认 UI 设计桥接与工作流已无生产 manifest writer,只写 `ui-design` / `ui-design-doc`。 -- [x] 非 canonical 原值留痕为「原始串 + 调用上下文」,由 `shared-contracts` 的可注册回调 `set_non_canonical_asset_kind_reporter()` 交给 AGC 壳的 `app_log!`(2026-09-17 起不再用 `tracing` / `kind-observability`);生产 writer 只传正式枚举成员。 -- [x] ts-rs 生成路径为 `packages/shared/src/contracts/generated/`(2026-09-17 从 `apps/ai-game-creator-shell/src/contracts/generated/` 迁出),命令为 `cargo test -p shared-contracts --features ts-bindings export_bindings`(枚举自带 `export_to`),生成目录已在 `.prettierignore` / eslint `ignorePatterns` 中保持原始格式。 -- [ ] 接入 CI verify(在 CI 中跑一次 `export_bindings` 并断言生成文件无 diff)。 - -## 已确认的 manifest kind 入口(M0 审计结果) - -下列位置已经确认直接承载或生产 `GameCreationAppAssetManifestEntry.kind`,后续迁移必须逐项完成: - -| 位置 | 当前事实 | 后续动作 | -| --- | --- | --- | -| `src-tauri/src/assets.rs:584-604` | `register_local_asset_at` 以 `&str` 接受 kind 并转交登记 | 参数改为 Rust enum;边界字符串集中解析 | -| `src-tauri/src/assets.rs:563-566` | 普通上传根据内容推断 kind 后登记 | 推断函数返回 enum;无法判断返回 `Unknown` 并 trace,禁止 `asset` fallback | -| `src-tauri/src/assets.rs:791-806` | 画板导出图层登记资源 | 推断结果直接使用 enum | -| `src-tauri/src/assets.rs:916-934` | 平台资源同步从 payload `assetKind` 登记 | 入口解析成 enum;未知值 `Unknown` + trace | -| `src-tauri/src/assets.rs:1871-1916` | manifest 新增/更新资产并写入 kind | 禁止裸字符串和隐式 alias/fallback | -| `src-tauri/src/commands.rs:2094-2129` | Tauri `register_local_asset` 接收外部 kind | 解析边界收紧为 enum/Unknown | -| `src-tauri/src/commands.rs:2672-2711` | 字体导入生产路径登记 `"font"` | 正式保留 `Font` enum variant | -| `src-tauri/src/commands.rs:2784-2803` | 字体登记测试/辅助路径 | 与生产字体 kind 一致 | -| `src-tauri/src/project/resource_editor.rs:3806-4065` | 资源派生/替换构造 manifest asset | `source_subtype` / `asset_kind` 只在确认是 manifest kind 时改 enum;operation 临时类型另行排除 | -| `src-tauri/src/ui_editor/workflow.rs:687-749` | UI 设计文档与图片资源登记 | `ui-design-doc` / `ui-design` 使用 enum | -| `src-tauri/src/ui_editor/resource_bridge.rs:121-139` | UI 设计文档生产登记 | 使用 `UiDesignDoc` enum variant | -| `src-tauri/src/agent/direct_runtime.rs:2462-2469` | 恢复图集登记仍传 `"art-spritesheet"` | manifest 写入改为 `IconSpritesheet`;恢复协议字符串单独审计 | -| `src-tauri/src/agent/generation/canvas_generation.rs:6816-6828` | 切片 manifest 条目仍写 `"art-spritesheet-slice"` | manifest 写入改为 `Icon`;切片协议标识不自动替换 | -| `src-tauri/src/agent/direct_tool_bridge.rs:1126-1183` | Agent 资源投影读取 manifest kind | 改为消费 enum,序列化边界仍输出 kebab-case | -| `src-tauri/src/agent/direct_codex_user_item/wire.rs:66-96` | Agent 引用投影按 manifest 身份解析资源;不再展示裸 kind | 已消费 enum;UI 文档分支只用 `UiDesignDoc` 身份判据,无字符串展示 | - -## 已确认的 shell TS 消费方 - -这些文件目前通过 `packages/shared/src/contracts/gameCreationApp.ts` 或手写 `string` 消费资源 kind,需迁入 shell 生成绑定: - -- `src/features/project-workspace/resourceReferences.ts` -- `src/features/project-workspace/ResourceReferenceInput.tsx` -- `src/features/project-workspace/SupervisorChatOnlyView.tsx` -- `src/features/project-workspace/ProjectSupervisorView.tsx` -- `src/features/project-workspace/ProjectWorkspaceChatPane.tsx` -- `src/view/project-development/index.tsx` -- `src/view/project-development/ResourceClassificationPanel.tsx` -- `src/view/project-development/ResourceRenameDialog.tsx` -- `src/view/project-development/resourceProjectionModel.ts` -- `src/features/resource-canvas/resourceCanvasBottomToolbarModel.ts` -- `src/features/resource-canvas/resourceCanvasGenerationPanelView.tsx` -- `src/features/resource-canvas/ResourceCanvasAssetGenerationPanelView.tsx` -- `src/features/resource-canvas/resourceVersionReplacementModel.ts` -- `src/components/AssetImporter/utils.ts` -- `src/components/AssetImporter/index.tsx` -- `src/components/AssetImporter/settings.ts` -- `src/services/clientApi.ts` -- `src/view/ui-editor/useUiEditorPage.ts` -- `src/features/ui-editor/uiDesignResourceBridge.ts` - -其中 `resourceCanvasBottomToolbarModel.ts:243,258` 和 `resourceProjectionModel.ts:326` 已明确出现 `art-spritesheet` / `ui-prototype`,需回到调用链判断它们是 manifest kind 还是生成入口协议值,不能文本全局替换。 - -## 旧值生产状态初判 - -| 值 | 已发现位置 | 初判 | -| --- | --- | --- | -| `font` | `commands.rs:2672,2787`;UI Editor 字体登记 | 正式 manifest kind,保留 | -| `audio` | `assets.rs:495`;上传推断与本地文件类型 | 正式 manifest kind,保留 | -| `sound-effect` | `direct_tool_bridge.rs:104-116`;Agent 音频工具 | 正式 manifest kind,保留 | -| `background-music` | `direct_tool_bridge.rs:104-116`;Agent 音频工具 | 正式 manifest kind,保留 | -| `asset` | `assets.rs:537` 未知上传兜底;`assets.rs:1882` 空 kind 兜底 | 错误 fallback,改为 Unknown/显式失败后删除 | -| `art-spritesheet` | `direct_runtime.rs:2465`;canvas generation 多处 | 既有 manifest/协议混用,逐处拆开 | -| `art-spritesheet-slice` | `canvas_generation.rs:6818`;direct runtime 多处 | manifest kind 改为 `icon`,协议标识另留 | -| `game-background` | canvas generation 选项与 runtime 阶段 | manifest kind 改为 `scene`,阶段标识另留 | -| `game-art` | canvas generation 默认值/测试 | manifest kind 改为 `image`,生成请求字段另审 | -| `illustration` | direct runtime 测试/恢复路径 | manifest kind 改为 `image`,其他用途另审 | -| `character-art` | manifest/API 白名单与测试 | manifest kind 改为 `character`,API 参考不改 | -| `ui-prototype` | UI workflow 检查、资源 bridge、TS 画布选项 | manifest kind 改为 `ui-design`;workflow 输入另审 | -| `ui` | 旧 bridge/测试与外部输入 | 不再 alias;未知值进入 `Unknown`,逐处确认生产残留 | -| `animation` | 旧映射及文本/阶段判断 | 不再 alias;仅 manifest kind 的位置改为 `character-animation` | -| `game-entry` / `game-script` / `game-style` | runtime 代码文件登记 | manifest kind 改为 `code`;文件阶段标识不改 | - -## 本轮明确排除的同名字段 - -以下命中不属于本 PR 的 `GameCreationAppAssetKind`,只记录边界,不修改: - -- `source.kind`:`Uploaded / Generated / Canvas`,表达资源来源。 -- `source.generationKind`:包含 `ui-workflow.completed`、`project-file`、`icon-spritesheet` 等工作流/生成标识。 -- `mediaType`、MIME、扩展名和文件分类器。 -- Agent group、task kind、workflow stage、路径/目录名、tracking scope、插件 kind。 - -## 下一步审计动作 - -- [ ] 为每个“旧值生产状态初判”补充真实调用链和测试证据。 -- [ ] 将 manifest kind 与 generation/request kind 的复用关系改为显式转换,不共享裸字符串。 -- [ ] 确认 `Unknown` 在上传推断、外部 payload、manifest 读取三条入口的日志字段。 -- [ ] 完成 `packages/shared` import 使用方迁移清单,确认删除文件不会留下跨包引用。 -- [ ] 完成后更新本文件,关闭 M0 里程碑,再创建代码里程碑的实施计划。 - -## manifest 构造器逐处清单 - -| 位置 | 当前 kind | 生产/测试 | 决定 | -| --- | --- | --- | --- | -| `src-tauri/src/assets.rs:1914-1916` | 上游 `kind.to_string()` | 生产公共写入边界 | 改为接收 `GameCreationAppAssetKind`,统一负责序列化 | -| `src-tauri/src/project/resource_editor.rs:3806-3809` | `source_subtype.to_string()` | 生产派生资源 | 先把 `source_subtype` 解析/转换为 manifest enum;临时 operation subtype 不得混入 | -| `src-tauri/src/project/resource_editor.rs:4059-4065` | `asset_kind` | 生产派生资源 | 改为 manifest enum;调用方显式转换 | -| `src-tauri/src/agent/generation/canvas_generation.rs:6816-6828` | `art-spritesheet-slice` | 生产切片回写 | 改为 `Icon`;只保留协议层切片标识在独立字符串字段 | -| `src-tauri/src/ui_editor/workflow.rs:1468-1475` | 测试 helper 参数 `kind` | 测试 | helper 改为 enum,fixture 只使用正式成员 | -| `src-tauri/src/project/manifest/recovery_tests.rs:181-183` | `character` | 测试 fixture | 改为 enum variant | -| `src-tauri/src/agent/direct_tool_bridge.rs:3189-3192` | `art-spritesheet-slice` | 测试 fixture | 如果测试 manifest 语义,改为 `Icon`;协议测试另造明确协议字段 | -| `src-tauri/src/agent/direct_tool_bridge.rs:3246-3249` | `character-animation` | 测试 fixture | 改为 enum variant | -| `src-tauri/src/agent/direct_tool_bridge.rs:3297-3299` | `spec` | 测试 fixture | 改为 enum variant | -| `src-tauri/src/agent/direct_tool_bridge.rs:3339-3342` | `ui` | 旧兼容测试 | 删除 alias 断言;改为 `Unknown` + trace 测试或移至 parser 边界测试 | -| `src-tauri/src/project/resource_dependency_graph.rs:652-656` | `test` | 测试 fixture | 改为 `Unknown`,明确测试未知 kind 投影,不得继续写任意字符串 | -| `src-tauri/src/commands.rs:2888-2892` | `font` | 测试 fixture | 改为 `Font` enum variant | - -## shell TS 类型迁移清单(已发现裸 string) - -以下字段目前仍是 `string` / `string | null`,但若其语义是 manifest `assetKind`,必须改为生成的 `GameCreationAppAssetKind`;若只是外部 API 开放值,保留并在清单中标注转换边界: - -- `src/services/clientApi.ts:198` -- `src/view/ui-editor/useUiEditorPage.ts:81,1077` -- `src/components/AssetImporter/utils.ts:7,32,114` -- `src/components/AssetImporter/index.tsx:61` -- `src/features/resource-canvas/resourceCanvasBottomToolbarModel.ts:79` -- `src/features/project-workspace/DeveloperProjectPanels.tsx:15` -- `src/features/project-workspace/ResourceReferenceInput.tsx:104` -- `src/features/resource-canvas/resourceVersionReplacementModel.ts:232-245` -- `src/features/project-workspace/resourceReferences.ts:101-134` -- `src/view/project-development/resourceProjectionModel.ts:319-345` -- `src/features/ui-editor/uiDesignResourceBridge.ts:55-87` -- `src/App.tsx:1262,10083` - -特别处理: - -- `resourceCanvasBottomToolbarModel.ts:243` 的 `art-spritesheet` 和 `:258` 的 `ui-prototype` 当前位于生成入口选项,需先确认该字段是否传入 manifest 登记;若只是 API/生成请求 kind,使用显式转换函数,不把旧值加入 manifest enum。 -- `resourceProjectionModel.ts:326`、`uiDesignResourceBridge.ts:87` 是直接比较 manifest asset kind 的消费点,必须跟随生成绑定迁移到 enum。 -- `SupervisorChatOnlyView.tsx`、`ProjectSupervisorView.tsx` 等仍直接从 `packages/shared` 导入 manifest 类型,需在删除旧文件前完成 shell 内导入收口。 - -## 已迁移的 TS 边界(增量) - -- `packages/shared/src/contracts/gameCreationApp.ts`:直接 re-export Rust 生成的 `GameCreationAppAssetKind`,`parseGameCreationAppAssetKind(raw, context)` 未知输入 `console.warn` 记录 `rawKind` / `sourceContext` 并返回 `unknown`,不做旧 alias 转换;`src/contracts/assetKind.ts` 这层 shell 内重复实现已删除(2026-09-17)。 -- `src/features/project-workspace/resourceReferences.ts`:资源引用 kind 改为生成枚举类型并通过 parser 收口。 -- `src/view/project-development/index.tsx`:画布引用入口通过同一 parser 构造资源引用 kind。 -- `src/features/ui-editor/uiDesignResourceBridge.ts`:UI 原型 manifest kind 只接受 `ui-design`,UI 文档链接只接受 `ui-design-doc`;旧 `ui-prototype` 不再 alias。 - -其余 `packages/shared` import 和前端 manifest `kind: string` 字段仍未迁移,继续作为后续小切片,不在本次提交中伪装完成。 diff --git a/docs/project-memory/todos/【待办】主站SPA路由白名单与前端路由源不一致-2026-09-24.md b/docs/project-memory/todos/【待办】主站SPA路由白名单与前端路由源不一致-2026-09-24.md new file mode 100644 index 000000000..359212d08 --- /dev/null +++ b/docs/project-memory/todos/【待办】主站SPA路由白名单与前端路由源不一致-2026-09-24.md @@ -0,0 +1,42 @@ +# 【待办】主站 SPA allowlist 与前端路由源不一致 + +更新时间:`2026-09-24` + +状态:部分关闭。共享组件展示页(`/components`、`/design-system`)的缺失已在本轮补齐;剩余 5 条 `/games*` 路由属冻结的游戏分发系列,`npm run check:nginx-spa-routes` 与 `npm run check:pingora-route-parity` 仍为红灯。 + +## 现象(2026-09-24 实跑) + +- `npm run check:nginx-spa-routes` → **exit 1**:`deploy/nginx/genarrative.conf`、`deploy/nginx/genarrative-dev-http.conf`、`deploy/container/nginx.conf` 三份模板的 SPA allowlist 原本都缺 `/components`、`/design-system`、`/games`、`/games/detail`、`/games/play`、`/games/mine`、`/games/publish`。 +- `npm run check:pingora-route-parity` → 同样失败:它 `import { expectedMainSpaRoutes } from './check-nginx-spa-routes.mjs'`,而后者在模块级就执行整套校验。 +- 前端事实源:`src/routing/activeAppPageRoutes.ts` 的 `STAGE_ROUTE_ENTRIES`(含 5 条 games)与 `src/routing/activeAppRoutes.tsx` 的 `/components`、`/design-system`。 + +## 影响 + +生产模板里未列入 allowlist 的路径落到 `location /` 的 `try_files $uri $uri/ =404`,因此这些 SPA 深链在公网返回 404,而不是渲染 index.html: + +- `/components`(兼容别名 `/design-system`):共享组件展示页,技术文档明确它「不经过账号 Gate」,用于网站与客户端接入前的视觉回归和人工验收。 +- `/games`、`/games/detail`、`/games/play`、`/games/mine`、`/games/publish`:游戏分发系列的目录、详情、游玩、我的与发布页。 + +## 历史(为什么红了这么久) + +- `c5200c7d4`(2026-08-26,PR #202)新增 `/components`、`/design-system` 路由与展示页,nginx 模板没有同步,门禁从那时起就是红的。 +- `39aed2e48`(2026-09-20)曾把这两条连同 games 路由一起补进三份模板的同一行正则。 +- `429f991bd`(2026-09-20,回滚误入 master 的游戏分发 WIP)把整行改回 `creation|editor/canvas|profile|project`,两条展示页路由被连带移除。 +- decision-log 2026-09-23「游戏发行包上限提升到 200 MiB」条目已把这处失败记为「改动前同样失败,与本次口径无关」。 +- `.gitea/workflows/project-ci.yml` 没有运行 `check:nginx-spa-routes`,根 `npm run lint` 也不含它,所以这盏红灯长期只在人工执行时可见。 + +## 本轮处理(2026-09-24) + +- 三份模板的 SPA 正则加回 `components|design-system`(一行 × 3 文件),展示页深链在模板层面恢复:`location ~* "^/(?:components|creation|design-system|editor/canvas|profile|project)/?$"`。 +- 复跑 `npm run check:nginx-spa-routes`:失败清单从 7 条降到 5 条,只剩 `/games`、`/games/detail`、`/games/mine`、`/games/play`、`/games/publish`。 +- 相关门禁未受影响:`npm run check:release-origin-config`、`npm run check:production-ops`、`npm run check:maintenance-page`、`npm run check:preview-deployer` 全部通过。 + +## 剩余修法(游戏部分) + +把 5 条 games 路由加回三条正则,并同步 `docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md` 的 SPA allowlist 表(必要时还有 `deploy/pingora/nginx-route-parity.matrix.json`),门禁才会真正转绿。该部分属游戏分发系列,按用户本轮要求不推进,随阶段 A 验收结论一并处理。 + +## 关闭条件 + +1. `npm run check:nginx-spa-routes` 与 `npm run check:pingora-route-parity` 通过,三份模板的 allowlist 集合与前端路由源逐条一致。 +2. 大小写与尾部斜杠容忍、`/creation/not-exist` 等未知路径仍返回 404 的判据不被放宽。 +3. 游戏部分补齐前,本文件保持打开,不能把「门禁仍红」当成已收口。 \ No newline at end of file diff --git a/docs/project-memory/todos/【待办】引用输入区后续收口-2026-09-24.md b/docs/project-memory/todos/【待办】引用输入区后续收口-2026-09-24.md new file mode 100644 index 000000000..a73e7bcf1 --- /dev/null +++ b/docs/project-memory/todos/【待办】引用输入区后续收口-2026-09-24.md @@ -0,0 +1,28 @@ +# 【待办】引用输入区后续收口 + +状态:待决策与真机验收。承接已完成的「引用输入区重构与宿主注入」与「引用粘贴解析」两轮实现(其权威结论见 [`【ADR】引用候选由宿主注入-2026-09-22.md`](../../adr/【ADR】引用候选由宿主注入-2026-09-22.md) 与 `decision-log.md` 的 2026-09-22 条目;两份临时计划已按流程删除,历史由 Git 保存)。本文件只登记仍然开放、有人接手即可执行的事项。 + +## 1. 归一化撞名是否要在候选菜单提示(需产品决定) + +`hero v2` 与 `hero-v2` 经 `normalizeMentionName` 折成同一个 token,目前只在解析侧兜住(同名多候选一律按文本保留,不猜身份),候选菜单不提示冲突。 + +- 下一决策点:是否在候选菜单标出「这两个素材会折叠成同一提及」;如果要提示,还要决定是禁止其中一条被 `@`、还是保留两条但让用户看到冲突标记。 +- 关闭条件:给出明确取舍并落到 ADR / 决策记录;若选择不改,同样在决策记录里写明「接受折叠,不提示」作为终态。 + +## 2.(已关闭,2026-09-24)`resource-reference-*` CSS 类名不改名 + +审计结论:原条目假设「类名与选择器会短暂不一致、需要同批改名」,但现状已经不是这样。 + +- 选择器常量 `RESOURCE_REFERENCE_OVERLAY_SELECTOR`(`resourcesReferences.ts`)正好是 `.resource-reference-picker, .resource-reference-menu`,指向的就是这两个组件渲染的类,不存在需要「同批对齐」的错位。 +- 类名逐条与归属组件同名:`ResourceReferenceInput` → `resource-reference-input*`、`ResourceReferencePicker` → `resource-reference-picker*`、`ResourceReferenceChip` / `AttachmentReferenceChip` → `resource-reference-chip*`;`resource-reference-input-actions` 与 `resource-reference-menu` 是被输入区与选择器共用的锚点,属于有意共享。 +- 规模核对(2026-09-24 复核,比原条目记录更准):`src/styles.css` 80 处 + `resourceCanvasChrome.css` 2 处,共 82 处 `resource-reference` 选择器;src 与 tests 合计 19 个文件命中、测试里 35 行断言指向这些类名。也就是说改名是纯机械改动、82 处选择器 + 35 行断言一起动,而收益只是换一个同样贴切的词。 +- 决策:**接受现状,不改名**。没有现役调用方、公开契约或样式隔离上的问题需要靠改名解决;等真有新的命名口径(例如引用输入区整体改名)时,再与选择器常量和断言一次性同批改。 + +输入区与面板的 CSS 类名逐字保留至今,本轮只更新上面这条关闭结论,未动类名、选择器常量、样式表或断言。 + +## 3. 引用输入区真机手感验收 + +自动化只覆盖了行为,未覆盖触感与落点。 + +- 待验收项:候选菜单位置、面板内滚轮、附件插入位置、`@` 触发钮落点。 +- 关闭条件:在真实 AGC 客户端里逐项确认并记录证据(截图或录像),不接受以 jsdom 用例替代。 diff --git a/docs/project-memory/todos/【待办】画布验收后续修复-2026-09-18.md b/docs/project-memory/todos/【待办】画布验收后续修复-2026-09-18.md index 5eab4da0b..7c400ce32 100644 --- a/docs/project-memory/todos/【待办】画布验收后续修复-2026-09-18.md +++ b/docs/project-memory/todos/【待办】画布验收后续修复-2026-09-18.md @@ -87,3 +87,16 @@ 先核对测试包/提交,避免旧包反馈与已合入修复混淆。每个问题先复现、明确原因与最小修复,再补回归和独立 review;复杂需求按现有规范驱动流程推进。首批本地通过不等于远程 CI 或真实 Provider 验收通过,遗留 Rust shard 2 失败仍需跟踪实际 SHA。不得为验证擅自提交付费生成、部署或修改他人项目。 完成条件:逐项记录修复提交、实际执行的检查和客户端验收;长期规则回归主规范,全部关闭后删除本待办。 + +### 2026-09-24 文档全文预览入口复验 + 场景缺 key 修复 + +- 「文档全文预览入口不可用或不可发现」在当前版本**可用**:新增回归 `projectResourceLiveIntegration.test.tsx` 的「文档卡选中后工具条给出「预览」入口,点开是读取后的全文预览」——打开文档栏、选中文档卡、工具条出现「预览」、点击打开 `文档预览` 浮层、浮层显示 `read_local_project_text_preview` 读回的正文(不是卡面 3 行摘要),且不再停在「正在加载文档…」。 +- 同一用例顺带钉住一个**真实缺陷并修掉**:`ResourceBookScene` 的 `renderTitlebar` 返回的标题栏元素没有 `key`,而它在 `plan.map(...)` 里作为数组子节点(钉在视口上的那一组)使用,React 会报缺 key 警告却照常渲染,因此长期无人发现。已补 `key={group.category}`;用例里同时断言整段流程没有该警告,变异验证:拿掉 key 后该断言变红。 +- 「不可发现」的最可能原因(证据,未改动):选中工具条用 `OverflowActions` 渲染(`src/components/image-editor/ImageCanvasSelectedLayerToolbarView.tsx:154/216`),调用侧固定 `maxVisibleActions={5}`(`src/view/project-development/index.tsx`)——文档卡动作多时「预览」会落进「更多」。是否调整可见优先级(例如把「预览」固定在可见位)属于 UI 取舍,等真机确认后再改,不在本轮擅自调整。 +- 本机执行:`npx vitest run tests/projectResourceLiveIntegration.test.tsx --root apps/ai-game-creator-shell` 33 passed;`npm run ai-game-creator-shell:check:web` 185 files / 1809 passed;改动文件 prettier / eslint 通过。 +- 仍未做:动画生成失败的真实复现与定位、标签面板查看更多标签、资源面板多选卡死、卡片全类型重设计、画布内任务浮层、替换交互与聊天引用后续需求,以及全部真机观感验收。 +- 「标签面板无法查看更多标签」定位到成因并修复:筛选面板「自定义标签」区的高度夹紧写在**内层** `.game-resource-filter-panel__card`(`max-height: calc(100% - 72px)`),而内层的包含块是高度 auto 的定位锚点 `.game-resource-filter-panel` —— 百分比 max-height 在这种情况下按 `none` 处理,面板于是不受限地向上增长;它的定位祖先 `.game-resource-book-manager` 是 `overflow: hidden`,所以标签一多,顶部被裁掉,`overflow-y: auto` 也永远等不到滚动。修复:把夹紧与滚动上移到定位锚点(百分比相对管理区的确定高度解析),内层改为 `max-height: none`。 +- 该修复由新增的 `tests/resourceFilterPanelStyle.test.ts` 两条声明级守卫钉住(jsdom 不排版,按仓库既有做法解析真实生效声明);变异验证:把百分比放回内层、或把锚点的夹紧改成 `none`,对应断言分别变红。 +- 「资源面板多选后卡死」的代码级定位(一条确定路径,本轮已改):框选(marquee)在**每次 pointermove** 都重算命中集合并无条件写入 `selectedResourceIds`;指针在同一片空白里移动时集合往往没变,但每帧都换一个新数组身份,于是依赖该数组的 memo(如批量标签目标解析)与接收它的面板 props 跟着每帧重算/重渲染——卡片多时表现为「多选后卡顿、像卡死」。修复:新增 `sameResourceIdSelection`(忽略顺序的集合等价判据,重复项退回逐项比较)并在框选写回处复用上一份数组身份;`resourceBookModel.test.ts` 增两条单测(集合等价 / 不等价);2026-09-24 复核:把 `sameResourceIdSelection` 改成恒 `false` 后该文件精确 1 条失败(16 条中的 1 条)、其余通过,证实是这两条单测在守它。 +- 行为不回归由既有框选用例覆盖:`resourceCanvasManualLayout.test.tsx` 的「资源卡右键平移保留选中,左键空白拖动仍框选」与 `appSurface` 的框选颜色/几何用例继续通过。 +- 诚实边界:本机没有可复现的「卡死」现场(需要大项目 + 真机),本轮只消除了一条**确定**的每帧重算路径;是否还有其它卡顿源(卡片预览订阅、布局重排等)要用真机 Profiler 复看,待现场确认。 diff --git a/docs/project-memory/todos/【待办】计划收口剩余项索引-2026-09-24.md b/docs/project-memory/todos/【待办】计划收口剩余项索引-2026-09-24.md new file mode 100644 index 000000000..11ae70ac2 --- /dev/null +++ b/docs/project-memory/todos/【待办】计划收口剩余项索引-2026-09-24.md @@ -0,0 +1,62 @@ +# 【待办】计划收口剩余项索引 + +生成时间:2026-09-24。用途:把 `docs/project-memory/plans/` 里尚未完成或尚未验收的条目集中列出,方便一次性安排真机、账号与流水线验收。**本文件只做索引,权威内容仍在各自的计划文件;第四节把 `docs/project-memory/todos/` 里不挂在计划上的开放事项一并列出。** + +## 一、等待用户决定(1 个功能决定,涉及 2 份计划) + +| 计划 | 卡点 | +| --- | --- | +| `【里程碑】项目客户端占用锁收敛-2026-09-14.md` 与对应实施计划 | 验收标准第 4 条「客户端占用入口与 Runtime 写入入口不各自维护第二个项目级锁文件」需要先定「谁写项目」:A)Runner 成为唯一写者、GUI 写命令经 Runner 转发(需先改主规范并按 SDD 立项);B)修改 execution-owner 的 OS 锁安全合同(与 decision-log 2026-07-12 的安全合同冲突)。其余 1/2/3/5 条已实测成立。 | + +## 二、需要真实环境(按环境分组,共 17 份计划) + +| 需要什么 | 计划 | 未勾选或未验证内容 | +| --- | --- | --- | +| macOS 构建节点 | `【里程碑】Mac本机构建节点接入-2026-09-18.md`、`【实施计划】Mac本机构建节点接入-2026-09-18.md` | 本机 Mac 节点接入与网络前置;状态 `accepted-with-open-items` / `preparing-network-required` | +| Windows 真机 | `【里程碑】Mac客户端随包运行依赖补齐-2026-09-18.md`、`【实施计划】Mac客户端随包运行依赖补齐-2026-09-18.md` | `awaiting-windows-acceptance`:随包依赖在 Windows 侧的安装与运行验收 | +| 用户签收 | `【里程碑】Mac通用安装包与构建管线-2026-09-18.md`、`【实施计划】Mac通用安装包-2026-09-18.md` | `awaiting-user-acceptance`:通用安装包与构建管线签收 | +| macOS 节点 + 真机升级 | `【里程碑】AGC macOS渠道更新落地-2026-09-17.md` | 4 条:`dev-mac` 清单两平台键与可下载一致性、macOS 客户端真实更新(检查/下载/安装/重启)、旧版本升级、未签名或未公证失败关闭 | +| 真实发布与流水线 | `【里程碑】AGC更新发布管线渠道化-2026-09-17.md`、`【里程碑】AGC客户端更新切换到官方更新插件-2026-09-17.md` | 渠道化:发布后 OSS 三者一致、Jenkins 日志与归档不含私钥;官方插件:篡改包必须拒绝安装并清理临时文件 | +| 双渠道真机 | `【里程碑】AGC渠道安装身份隔离-2026-09-21.md` | `dev` 与 `release` 在同一台设备并存并可各自原地更新 | +| 真实 app-server 会话 | `【里程碑】DirectProject聊天真相源收敛-2026-09-16.md` | 回合中杀进程重开后的顺序与忙碌态、运行中页面重进与终止 | +| 真实客户端 | `【里程碑】对话总耗时与动态工具计时-2026-09-18.md`、`【里程碑】多选素材批量标签-2026-09-17.md`、`【里程碑】画布验收问题统一修复-2026-09-17.md` | 计时:真实客户端切项目、取消后重发、重开历史与真实 Provider 通知;批量标签:真实客户端点击与跨窗口写盘;画布:末版浮层几何与真实 Provider + IPC 全流程 | +| 本地数据库 + 新客户端 | `【里程碑】项目自动上传与后台工程下载-2026-09-19.md` | 条目 9:`dev:api-server` 就绪后的 HTTP 联调、新客户端安装版的隔离实机自动上传 | +| GameAgent 回归 | `【里程碑】策划Agent回合模型选择生效-2026-09-20.md` | 条目 5 与条目 7 已于 2026-09-24 补齐本地证据并勾选(Rust `design_runtime::tests` 24 passed、`model_selection` 2 passed、`canonical_agent_reasoning_effort` 1 passed、AGC `appSurface` 191 passed / 9 skipped、`conversationModelSelect` 29 passed);整份计划现已无未勾选条目,只剩真实 Provider 与桌面端单回合 smoke(需真实账号与费用) | +| 真机 + 真实 Provider | `【里程碑】退役策划Agent V1V2解耦清理-2026-09-15.md` | 源码级判据已全部勾选(2026-09-24 补上条目 5:退役提交对做游戏 DAG 只有最小修复,`autonomous_game_build` 28 passed);剩「做方案」新项目进入 Design Agent、已有会话恢复、澄清/阶段审批回合的真机连续验收 | + +## 三、按约定保持原状(3 份计划,28 条未勾选) + +| 计划 | 说明 | +| --- | --- | +| `【里程碑】游戏分发目录详情与在线游玩-2026-09-18.md`(状态 `accepted(阶段 A 未验收)`) | 28 条验收项属游戏分发阶段 A/C 系列,按既定边界本轮不推进,等阶段 A 验收结论 | +| `【实施计划】游戏分发阶段A领域合同-2026-09-19.md` | 同上,状态 `in_progress` | +| `【实施计划】游戏分发阶段C-AGC发布资料AI生成-2026-09-23.md` | 同上,状态 `in_progress` | + +补充(2026-09-24 复跑,供解冻决策用):游戏分发系列**本地可跑的证据今天全绿**——`cargo test -p module-game-distribution` 13 passed、`cargo test -p api-server game_distribution` 26 passed、网页端 `src/components/game-distribution` + `gameDistributionClient.test.ts` 5 文件 / 54 passed、AGC 发布三条用例文件 24 passed。因此这 28 条未勾选项的瓶颈不在本地代码,主要是真实环境(独立 HTTPS 发行源与通配证书、CDN purge 与缓存窗口、200 MiB 档容量复跑、真机导航/沙箱观感)与阶段 A/C 的验收结论。 + +## 四、`docs/project-memory/todos/` 其余开放事项(不挂在计划上的) + +| 待办 | 现状 | 等谁 | +| --- | --- | --- | +| `【待解决】AI游戏创作高风险审批Rank-2026-07-20.md` | 2026-09-24 已补「现役实现取证」与 R1~R10 的 PRD 骨架(只列问题与硬约束,未冻结任何数值);前端 `approvalMode` 目前只是展示层,Rust 侧尚无该入参 | 产品 / 架构评审:是否按该 PRD 立项实现高风险审批 | +| `【待解决】版本绑定口径冲突-版本追加写全量与替换写窄-2026-09-13.md` | 两方案代价已写清,未裁定 | 你拍板 | +| `【待评估】UI编辑器字体跨运行时像素一致性-2026-08-19.md` | 评估结论已给出:不建议做像素级契约,建议把 BestFit 固化进导出产物 | 你确认是否接受该结论 | +| `【待办】引用输入区后续收口-2026-09-24.md` | CSS 类名改名一条已按现状关闭(接受不改名);剩「归一化撞名是否提示」与真机手感验收 | 产品决定 + 真机 | +| `【待办】画布验收后续修复-2026-09-18.md` | 三批修复与三项画布后续需求已落地本地;动画生成失败的真实复现、多选卡顿的现场 Profiler、以及全部真机观感仍未取证 | 真实客户端 + 现场 | +| `【目标编辑器适配】Unity与Unreal项目识别与导入-2026-09-11.md` | 明确「暂不实现」的新功能 | 排期决定 | +| `【待办】主站SPA路由白名单与前端路由源不一致-2026-09-24.md` | `check:nginx-spa-routes` 自 2026-08-26 起红灯;2026-09-24 已补回 `/components`、`/design-system`(失败清单从 7 条降到 5 条),剩 5 条 `/games*`;CI 与 `npm run lint` 都不含该门禁 | 剩游戏部分:属冻结的游戏分发系列,等阶段 A 验收结论 | + +## 五、已收口口径(供复核) + +- 74 份计划里 63 份为 `implemented-awaiting-runtime-acceptance`(含用括号写清边界的那批,含 `- Status:` 与表格两种写法);其余 11 份全部落在本文件一、二、三节里——这三节另外还列了 10 份状态已是 `implemented-awaiting-runtime-acceptance`、但仍有条目未勾选或未验收的计划,所以三节合计 21 份,不要与本条那 11 份混算。 +- 未勾选复选框从 85 条降到 43 条(2026-09-24 复算口径:`- [ ]` 行首复选框,74 份计划合计):本轮把已有本地证据的条目逐条勾选,并在每份计划里写了本轮的勾选依据或复验记录——多数是「逐条勾选依据(2026-09-24)」章节,另有「本轮复验(2026-09-24)」「本轮复核(2026-09-24)」写法,`【里程碑】DirectProject聊天真相源收敛-2026-09-16.md` 则把自动化证据直接写在条目里(`【自动化:…】`);仍勾不动的条目都能在依据里读到具体原因。 +- 仍为红灯的门禁(2026-09-24 实跑,与计划条目无关但需知晓):`npm run check:nginx-spa-routes`、`npm run check:pingora-route-parity`(`/components`、`/design-system` 已于本日补回,剩 5 条 `/games*` 的 SPA allowlist;详见 `【待办】主站SPA路由白名单与前端路由源不一致-2026-09-24.md`);两者都不在 CI 与 `npm run lint` 的覆盖范围内。 +- 其余门禁(2026-09-24 本机实跑):`ai-game-creator-shell:check:rust:crates` exit 0、`agc:plugins:test` 35 passed、`agc:plugins:native-test` 30 passed、`check:repository-ci origin/master` exit 0(含 admin-web typecheck 与生产构建)。 +- CI 全部 job 的命令(2026-09-24 起逐条对齐,本机实跑):AGC agent-run smoke `ai-game-creator-shell:agent-run:smoke` passed(本地 provider 桩,约 2.5 分钟);`cargo check --locked -p api-server --all-targets` 与 `-p spacetime-module` exit 0;两把 Cargo.lock 的「构建不改锁」判据以 `--locked` 全绿 + desktop 锁未被构建改动佐证。至此除「AGC Rust 四个分片跑全量(Windows 不实用)」与已记录的 Linux-only 门禁外,CI 每个 job 的命令都有本机结果。 +- CI 对齐的其余命令(2026-09-24 本机实跑):`npm run test:ci:frontend` 230 files / 2583 passed / 12 skipped、`npm run bgfilter-worker:smoke-test` 4 passed、`npm run build`(web + admin-web)exit 0;release 分组三步在 Windows 上全部可跑——`ai-game-creator-shell:build --no-bundle`(5m47s,产出 exe)、`desktop-shell:build --no-bundle`(1m29s)、`desktop-shell:stage-release-binary`(修掉 `new URL(...).pathname` 拼出 `F:\F:\…` 的 Windows 路径缺陷后通过)。 +- 运维类门禁(2026-09-24 本机实跑):`check:pingora-direct-preflight`、`check:pingora-canary-live-guard`、`check:pingora-direct-live-guard`、`check:nginx-pingora-canary` 直接通过;`check:production-api-release`、`check:production-api-deploy`、`check:production-health-patrol`、`check:pingora-release-readiness`、`check:pingora-tls-cert-sync` 是 Linux 生产机/CI 专属(`bash`+`chmod`、`/usr/bin/stat`、`systemctl`、写死的 `npm`、Linux 拷贝语义),本机不跑,已在 pitfalls 记录。 +- 唯一需要环境变量的是 `check:pingora-gateway-smoke`:本机要先设 `OPENSSL_CONF=C:\Program Files\Git\usr\ssl\openssl.cnf`(Strawberry OpenSSL 自带 config 路径不存在),同时脚本已修掉 Windows 二进制名与并发保护用例的竞态;设好变量后本机 `通过`。 +- `shells` 分组底层命令(2026-09-24 本机实跑):H5 HostBridge 8 文件 / 129 条、小程序壳 9 文件 / 35 条、`desktop-shell:test`、`desktop-shell:typecheck`、`mobile-shell:typecheck`、`mobile-shell:test` 全绿;`mobile-shell:config`、`mobile-shell:build-config`、`mobile-shell:export` 原为 Windows `npm.cmd EINVAL`,本轮改成「固定命令串 + shell」后三条都通过。 +- server-rs 全量 workspace(2026-09-24 本机实跑,`--exclude spacetime-module --no-fail-fast`):`api-server` 1124 passed / 11 failed(全部是 `wallet_refund_outbox` 的本机基线失败,`fs::hard_link` 在 `%TEMP%` 返回 PermissionDenied)、`server-manager-panel` 5 passed / 1 failed(`fc-match` 是 Linux 专属);其余 crate 全绿。这两类已记入 `pitfalls.md`,不作为代码信号。 +- AGC Rust 全量套件(2026-09-24):分片自检修掉一处重复 `#[test]` 后通过(`2936 tests, 4 shard(s)`,四片各 734 条互斥);分片 runner 也已支持 Windows(按 12 KiB 切块 argv,绕开 `spawn ENAMETOOLONG`)。但本机跑全量仍不实用:每次 `cargo test --no-run` 都要重新链接(并行 runner 进程会撞 `link.exe exit 1104`),且部分用例在本机纯 CPU 忙等(26 条 `background_agent_runtime` 过滤烧掉 35 分钟以上 CPU,单条单独跑 3.7 秒通过)。新模块定向 39 条通过;完整口径仍以 Linux CI 的分片 job 为准。 +- 最近一轮门禁(2026-09-24,代码改动已全部落地):`npm test`(2026-09-24 复跑,全量 JS/TS)417 files / 4396 passed / 26 skipped;`npm run ai-game-creator-shell:check:web` 189 files / 1832 passed / 14 skipped(较基准多出的 3 文件 19 条是 2026-09-24 新增的 `platformSessionRetry.test.ts` 7 条、`clientHttp.test.ts` 5 条与 `platformSession.test.ts` 7 条);`npm run lint`(含 `check:generated-bindings`)、`npm run check:doc-index`、`npm run check:encoding`、`git diff --check` 通过。此后本轮只改 `docs/` 下的 Markdown,未再动代码。 diff --git a/docs/project-memory/todos/【待解决】AI游戏创作高风险审批Rank-2026-07-20.md b/docs/project-memory/todos/【待解决】AI游戏创作高风险审批Rank-2026-07-20.md index 79f699f28..e559bbb2b 100644 --- a/docs/project-memory/todos/【待解决】AI游戏创作高风险审批Rank-2026-07-20.md +++ b/docs/project-memory/todos/【待解决】AI游戏创作高风险审批Rank-2026-07-20.md @@ -1,6 +1,6 @@ # AI 游戏创作高风险审批 Rank 待解决事项 -更新时间:`2026-08-25` +更新时间:`2026-09-24` 状态:未关闭;当前产品只启用严格审批,高风险审批不得开放。 @@ -8,16 +8,87 @@ 项目开发工作台规划“严格审批 / 高风险审批 / 无需审批”三档。严格审批可直接复用现有 Runtime 确认门禁;高风险审批仍缺少可执行 Rank 合同,当前不能由前端自行判断。 -## 待确定 +## 现役实现取证(2026-09-24) -- Rank 的事实源和版本号。 -- 成本、历史错误率、资源不可逆性、代码/命令副作用、外部发布等维度的权重。 -- 单动作 Rank 与批次 Rank 的聚合方式。 -- Rank 阈值由谁配置、如何审计和回滚。 -- 模型建议与 Runtime 强制规则冲突时的裁决顺序。 -- 计费发生前、外部调用前、项目写入前分别在哪个阶段执行门禁。 -- Runner 恢复、重复 action、reconciliation 和策略升级时如何保持确定性。 -- 普通用户可见的风险原因和不泄露内部诊断的展示格式。 +### 前端目前只是展示层,不能成为事实源 + +- 选项定义在 `apps/ai-game-creator-shell/src/view/project-development/approvalMode.ts`:`ApprovalMode = 'strict' | 'risk' | 'none'`;`risk` 的 detail 固定为「Rank 规则待定,当前暂不可用」且 `available: false`,`none` 同为 `available: false`。 +- 选择面板 `ApprovalModeDialog.tsx` 对 `available: false` 的选项只调用 `onNotice(option.detail)`,不写状态也不调后端:可点击、可看到原因,与下方「临时产品边界」一致。 +- 模式当前只活在 React 内存里:`chat/DirectProjectChatView.tsx:129` 与 `index.tsx:2383` 各自 `useState('strict')`。Rust 侧没有任何 `approval_mode` / `approvalMode` 入参(`rg` 命中的 `default_tools_approval_mode` 属 Codex CLI 客户端扩展配置,与工作台三档无关),`workspace_preferences` 也没有对应字段,刷新窗口即回到默认。 +- 结论:这一档 UI 目前是纯展示,任何「按模式放行 / 拦截」都还没有后端事实。Rank 合同落地时,模式本身也必须搬进 Rust,前端只渲染后端返回的当前模式与可用性——这同时是用户既定要求「React 不持有数据与网络 IO」在审批链路上的落点。 + +### Rust 已有的可复用门禁锚点 + +- 待审动作与确认回执:`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/pending_confirmation_ledger.rs` 的 `write_game_creator_agent_runtime_tool_confirmation` / `consume_game_creator_agent_runtime_tool_confirmation`,回执绑定 `action_fingerprint` 且一次性消费。 +- 付费提交前置:`agent/direct_paid_submission.rs::ensure_direct_paid_submission_dispatch`。 +- 项目写入:`project/write_lock.rs` 与 `project/filesystem.rs`。 +- 外部生成:`agent/generation/external_generation_state.rs`、`agent/generation/canvas_generation.rs`。 +- 命令执行与工具面:`command_sandbox.rs`、`command_exec.rs`、`agent/runtime_actions/tool_policy_snapshot.rs`。 +- 自治 / 无交互回合策略:`agent/runtime_actions/autonomous_policy.rs`。 + +## PRD 骨架(待评审,尚未冻结任何数值) + +以下每条只给出必须回答的问题与候选形态,不代表已决定;标 `【待定】` 的项需要产品与架构评审后才能进入实现。 + +### R1 Rank 的事实源与版本 + +- 【待定】Rank 由谁计算:Runtime 本地规则(确定性、可离线),还是 Provider 建议加 Runtime 复核。 +- 【待定】版本形态:独立 `rank-contract.v1`,或并入 `game-creator-pending-action` 版本族。 +- 硬约束:Rank 决策必须能从 durable 输入重放出同一结果,禁止依赖当前时间、随机数或 Provider 不可复现文本。 + +### R2 输入维度与权重 + +- 【待定】是否采用这些维度及其权重:成本(泥点 / Token / 外部 API 额度)、历史错误率、资源不可逆性、代码与命令副作用、外部发布与外呼、可回滚性。 +- 【待定】维度取值用离散档位还是连续分值;分档边界写在合同里还是写进可配置项。 +- 硬约束:输入必须来自 Runtime 已持久的客观事实(动作类型、参数、目标路径范围、金额或额度、同一 fingerprint 的上一次结果),不得由模型自报分值决定放行。 + +### R3 聚合:单动作与批次 + +- 【待定】批次 Rank 取最大单动作 Rank、求和,还是加权聚合。 +- 硬约束:批次内任一成员达到「必须确认」阈值时,整个批次先确认;未达阈值的成员不得因为同批次存在高风险成员而被静默合并展示。 + +### R4 阈值来源、审计与回滚 + +- 【待定】阈值由谁配置(随包发布默认值、远端配置、用户本地偏好),以及离线或未取到配置时的 fail-closed 形态。 +- 【待定】配置变更写入哪份 durable 记录用于审计;回滚时旧配置是否对进行中的 run 继续生效。 +- 硬约束:阈值变更不得让已存在的 pending 动作从「需确认」变成「已确认」;已发出的确认回执不因策略升级而失效或扩大授权范围。 + +### R5 模型建议与 Runtime 强制规则的裁决顺序 + +- 【待定】模型建议只能是「提高审批严格度」,还是允许在低风险区间降低严格度。 +- 倾向方案(待评审确认):模型建议只收不放,放行类建议必须有 Runtime 客观事实支撑,与 `autonomous_policy` 现有 fail-closed 风格一致。 +- 硬约束:Runtime 强制规则优先于模型建议;冲突时取更严格的一侧,并在审计里同时记录两侧取值。 + +### R6 门禁执行点 + +必须在副作用之前、且是唯一权威执行点: + +- 计费发生前:`ensure_direct_paid_submission_dispatch` 与平台生成接入点。 +- 外部调用前:外部生成、外呼、发布类动作。 +- 项目写入前:`project/write_lock.rs` 覆盖的写命令与文件写入。 +- 【待定】只读动作是否也执行 Rank(默认不执行)。 + +### R7 恢复、重放与确定性 + +- 【待定】Runner 恢复、重复 action、reconciliation 时重新计算 Rank,还是读取已持久决策。 +- 硬约束:同一 pending 动作重放必须得到同一 Rank 与同一审批结论;已消费确认回执不得二次生效;策略升级后进行中的 run 以启动时合同版本为准,或在恢复时显式重修并记录原因,两者必须二选一并写进合同。 + +### R8 用户可见展示 + +- 【待定】确认卡展示哪些字段:风险等级、触发维度(可读措辞)、影响范围(项目内相对路径或动作名)、预估成本。 +- 硬约束:不得暴露 provider、fingerprint、密钥、绝对路径或内部诊断;文案由 Rust 生成,前端只渲染。 + +### R9 验收与回归矩阵 + +- 计费、文件写入、命令、外部生成、批次动作、重放、reconciliation 各至少一组确定性回归。 +- 一组「Rank 未就绪或配置缺失必须 fail-closed」的回归。 +- 一组「阈值变更不得放宽已存在 pending 授权」的回归。 +- 真实环境项:至少一次真实 Provider 加真实客户端的端到端确认体验,以及一次断线重启后的恢复确认。 + +### R10 明确不在本期范围 + +- 「无需审批」档的安全合同同为 `available: false`,单独立项,不与 Rank 合并。 +- 不引入前端 Rank 计算,不引入前端阈值缓存,不允许前端根据模式自行放行。 ## 临时产品边界 @@ -28,7 +99,7 @@ ## 关闭条件 -1. PRD 冻结 Rank 输入、阈值、版本和恢复语义。 -2. Runtime 在副作用前执行同一 Rank 决策,前端只展示后端结果。 -3. 覆盖计费、文件写入、命令、外部生成、批次动作、重放和 reconciliation 回归。 -4. 普通用户界面能说明为何需要确认,但不暴露 provider、fingerprint、密钥或绝对路径。 +1. PRD 冻结 Rank 输入、阈值、版本和恢复语义(对应 R1 至 R4、R7)。 +2. Runtime 在副作用前执行同一 Rank 决策,前端只展示后端结果(对应 R5、R6)。 +3. 覆盖计费、文件写入、命令、外部生成、批次动作、重放和 reconciliation 回归(对应 R9)。 +4. 普通用户界面能说明为何需要确认,但不暴露 provider、fingerprint、密钥或绝对路径(对应 R8)。 \ No newline at end of file diff --git a/docs/project-memory/todos/【待解决】版本绑定口径冲突-版本追加写全量与替换写窄-2026-09-13.md b/docs/project-memory/todos/【待解决】版本绑定口径冲突-版本追加写全量与替换写窄-2026-09-13.md index a4a0a57d0..5d33a0703 100644 --- a/docs/project-memory/todos/【待解决】版本绑定口径冲突-版本追加写全量与替换写窄-2026-09-13.md +++ b/docs/project-memory/todos/【待解决】版本绑定口径冲突-版本追加写全量与替换写窄-2026-09-13.md @@ -26,3 +26,25 @@ ## 验证方式 追加一次版本后复算同一批资源卡的光环归属,把「是否回退」钉成回归。缺口:`apps/ai-game-creator-shell/tests/resourceVersionReplacement.test.tsx` 只看 IPC 载荷与 `onManifestChange` spy,观察不到光环移动。 + +## 决策材料(2026-09-24 复核) + +### 现状与证据 + +- 追加(宽):`project/manifest.rs` 的 `append_agent_game_iteration_version_at` 直接调用 `game_iteration_resource_bindings(manifest)`,后者把**当时 manifest 里全部 assets** 映射成绑定(`slotId = asset:{id}`,纯恒等映射)。 +- 替换(窄):`project/version_resource_replacement.rs` 只改写被替换的那个版本的绑定——源素材从集合消失、替换素材按源素材原位置插回(顺序稳定);这条是 `mutate_manifest_allowing_version_binding_rewrites` 放行的唯一写通道。 +- 规范本身有两种表述,冲突就在这里:主规范「版本绑定恒等化」一节写明 `game_iteration_resource_bindings` **退回纯恒等映射**(即宽口径);而「绑定改写语义」一节点明 `resourceBindings` 是**「该版本使用的素材集合」而不是槽位表**(即窄口径)。替换切片是在恒等化之后落地的,两者叠加才产生现场那条「替换后 A 失去光环、追加一版 A 又带上」。 +- 读侧现状:替换关系今天只存在于写侧审计 `asset.version_binding.replace` 与宿主会话状态(前端 `replacement`),manifest 的 `.previous` 副本装盘即删。也就是说**没有**可用于投影光环的持久读侧关系。 + +### 选项与代价(复核后的结论) + +- **选项 1:追加时继承上一版绑定**(推荐候选)。实现点集中在 `append_agent_game_iteration_version_at`:它本来就要读 `manifest.versions.last()`(父版本 id 已经取自那里),因此不需要新增持久化;需要先定一条规则说明新登记素材与已删除素材如何进出这份继承集合,并同步改主规范「恒等化」那节的措辞与幂等比较(`existing.resource_bindings == resource_bindings` 的判据)。 +- **选项 2:保持宽口径,改由替换关系投影光环**。代价明显更高:替换关系目前没有持久读侧,需要新增读侧数据(或把审计日志提升为正式读模型),并且与主规范「该版本使用的素材集合」的表述相冲突,等于要改规范的定义而不是改实现。 + +### 无论选哪一条,落地顺序 + +1. 先改主规范(`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的版本绑定两节),把「谁定义版本用了什么」写成一句话口径。 +2. 再改实现与定向回归:`src-tauri/src/tests/version_resource_replacement.rs`(现有「替换改写绑定且不新增版本」)、版本追加路径的用例、版本卡光环投影用例;并补一条「替换后追加一版,光环不回到被替换素材」的回归。 +3. 前端 `resourceBindings → 光环` 的投影不改(`index.tsx` 的版本卡渲染只消费绑定集合)。 + +本条目仍待你裁定;在裁定前我不改任何版本语义(这属于跨模块持久化口径,按仓库规范必须先改主规范再动代码)。 diff --git a/docs/project-memory/todos/【待评估】UI编辑器字体跨运行时像素一致性-2026-08-19.md b/docs/project-memory/todos/【待评估】UI编辑器字体跨运行时像素一致性-2026-08-19.md index 6c5ea43c0..1be407169 100644 --- a/docs/project-memory/todos/【待评估】UI编辑器字体跨运行时像素一致性-2026-08-19.md +++ b/docs/project-memory/todos/【待评估】UI编辑器字体跨运行时像素一致性-2026-08-19.md @@ -13,3 +13,26 @@ UI Editor 预览已使用浏览器真实排版测量 `BestFit`:同样式的不 - 比较目标浏览器 WebView 与后续正式运行时的字体回退、字形替换、换行和行高是否需要像素级一致。 - 如需一致,先确认权威运行时、目标平台与可接受误差,再设计可复现的字体夹具和视觉回归门禁。 - 不得把此评估误解为 `BestFit` 尚未实现,或重新引入仅取 `BestFit.max` 的近似逻辑。 + +## 评估结论(2026-09-24) + +### 现状取证 + +- 预览侧(浏览器):`useBestFitFontSize` 用不可见测量节点对容器实际尺寸做整数二分,取 `[min,max]` 中最大可完整容纳的字号;没有字号能容纳时回落 `min`。主规范「UI 编辑器资源与字体」一节(实施计划 2026-06-24 第 528 行)写的就是这条口径;`Fixed` 则直接用固定值。 +- 生成侧(导出产物):`src-tauri/src/ui_editor/html_renderer/component/text.rs` 里 `FontSizing::BestFit(range) => range.min().get()` —— **导出模板永远用 min**,并且生成器里没有任何运行期测量(无 `clientWidth` / `scrollWidth` / `ResizeObserver` / `measureText`),产物只是一个静态模板字符串(`export const … = \`…\``),字号以 `calc({size}px * UI_SCALE)` 写死。 +- 由此得到一个比「像素一致性」更靠前的事实:对 `BestFit` 文本,**编辑器预览显示的是测量出的适配字号,导出产物用的是下限 `min`**,两侧连「用哪个字号」都不一致。这不是浏览器与引擎的渲染差异,而是同一条链路里预览与产物不共享同一个决策结果。 +- 另有两类**天生不可消除**的差异,与本次问题无关但必须写进边界:① 绑定字体加载中/失败/悬空引用时回退系统字体;② 字形替换、字距、行高与抗锯齿由各运行时自己的排版引擎决定。 + +### 结论与建议 + +1. **不建议把「跨运行时像素级一致」定成正式契约。** 文本 shaping、字体回退与 hinting 属于各运行时的排版实现;把它写成契约只能靠「固定字体夹具 + 逐运行时截图 + 容差阈值」的视觉回归来近似,成本高、价值低,而且一旦引擎换版本就得重定基线。 +2. **该定成契约的是「产物确定性」:导出产物必须携带作者在编辑器里看到的那份字号决策。** 也就是把 `BestFit` 在**保存/导出时**解析成具体整数(或让生成器接收测量结果),产物里写解析后的数值,而不是永远回落 `min`;运行期不再做任何测量。 +3. 若将来确实要让引擎运行时消费这些 UI 文档(见待办「Unity 与 Unreal 项目识别与导入」),先在**产物格式**上定「字号 + 字体族 + 行高」三元组的可携带语义,再谈是否需要按运行时的容差视觉回归;在那之前不为引擎另做一套测量。 + +### 落地顺序(若采纳建议 2) + +1. 先改主规范:把「BestFit 只在预览测量」扩写成「预览测量 + 保存/导出时解析并固化」,并写清回落 `min` 的条件。 +2. 再改实现:UI State 需要一个「已解析字号」字段(或保存流程在写盘前把 `BestFit` 解析成 `Fixed`),生成器改为消费该值;这一步会改**持久化文档结构**,按仓库规范必须先改规范再动代码。 +3. 回归:编辑器预览与导出模板对同一份文档给出同一字号(新增一条「解析后导出值 = 预览值」的用例),外加「没有任何字号可容纳时导出仍为 min」。 + +本条目仍待你裁定是否采纳建议 2(要不要把 BestFit 固化进产物);在裁定前我不动 UI State 结构或生成器。 diff --git a/docs/technical/【前端架构】SSE客户端传输层收口约定-2026-06-03.md b/docs/technical/【前端架构】SSE客户端传输层收口约定-2026-06-03.md index e6198b20e..d9cc88c94 100644 --- a/docs/technical/【前端架构】SSE客户端传输层收口约定-2026-06-03.md +++ b/docs/technical/【前端架构】SSE客户端传输层收口约定-2026-06-03.md @@ -33,7 +33,7 @@ ## 验收 - `src/services/sseStream.test.ts` 覆盖 CRLF / LF 边界、UTF-8 尾部 flush、异常 JSON 跳过和提前停止取消 reader。 -- `src/services/llmClient.test.ts` 覆盖 OpenAI 兼容文本流、异常 JSON 跳过和 `[DONE]` 后提前停止。 +- `src/services/llmClient.test.ts` 覆盖 OpenAI 兼容文本流、异常 JSON 跳过和 `[DONE]` 后提前停止。**2026-09-24 修订**:`src/services/llmClient.ts` 与其测试已随旧创作链路退役删除,该条不再是现行验收项;现行 SSE 传输层验收由 `src/services/sseStream.test.ts`(已放回根 `vitest.config.ts` 的 include,2026-09-24)与各业务 client 的既有用例承担。 - `src/services/image-editor/editorAgentClient.test.ts` 覆盖会话 CRUD 和 `/messages` 普通 JSON 路由;画布 Agent 不纳入 SSE parser 验收。 - 已有 OpenAI 兼容文本流、NPC 聊天流、创作 Agent、创意互动 Agent、视觉小说运行态和充值订单状态测试继续通过。 - `npm run typecheck` 不产生新的类型错误。 diff --git a/docs/technical/【技术方案】AGC后端框架整理与演进路线-2026-09-18.md b/docs/technical/【技术方案】AGC后端框架整理与演进路线-2026-09-18.md index 9b3b9db71..d7f1ba816 100644 --- a/docs/technical/【技术方案】AGC后端框架整理与演进路线-2026-09-18.md +++ b/docs/technical/【技术方案】AGC后端框架整理与演进路线-2026-09-18.md @@ -1,6 +1,6 @@ # 【技术方案】AGC 后端框架整理与演进路线 -更新时间:`2026-09-18` +更新时间:`2026-09-23` ## 结论 @@ -49,7 +49,7 @@ flowchart TB PROJECT[Local Project Plane\nfiles / manifest / JSONL / locks / checkpoints] UI --> HOST - UI --> API + HOST --> API HOST --> CORE HOST --> ORCH HOST --> CONTRACT @@ -190,7 +190,7 @@ UI ### 云端资源/生成操作 ```text -AGC tool or UI +AGC tool or UI -> Local Rust Host -> api-server route -> auth + project ownership + idempotency -> module-* validation @@ -223,14 +223,28 @@ Local project snapshot 3. **文件系统单一入口**:任何 Agent 文件读写都经过项目 scope、写锁和受控工具;不能在 API 或前端加旁路写入。 4. **外部服务单一入口**:LLM、生成、OSS、认证等外部调用只经 `platform-*`,不能在业务 handler 里散落裸 HTTP。 5. **数据访问单一入口**:`api-server` 和本地需要的云端调用使用 `spacetime-client` facade,不直接拼 SpacetimeDB 请求。 -6. **前端只消费投影**:前端不推导正式业务状态,不直接访问本地项目数据库或 SpacetimeDB。 +6. **前端只消费投影**:AGC React 按离线前端设计,只负责展示、交互、输入草稿及短暂 UI 状态。正式数据、持久化、网络请求编排、重试和恢复由 Rust 本地宿主与云端控制面持有。React 通过领域命令表达用户意图,通过事件或 channel 接收结果,不在渲染/effect 中主动回写收到的正式状态,不直接访问本地项目数据库或 SpacetimeDB。 7. **身份与凭据分离**:同一身份的 access token 轮换不使在途 Run 失效;换号、退出或 origin 变化必须使旧 Run 停止后续副作用。 8. **可恢复优先**:持久动作、异步生成、Runner 续跑、外部结果回填和最终状态写入必须有稳定 ID、版本/CAS 或幂等键。 ## 当前缺口 +### 渲染层数据与 I/O 边界尚未完成 + +2026-09-23 已完成第一条可复核的网络下沉闭环:官方模型目录 GET /api/llm/models 由 Tauri `load_game_creator_llm_models` 持有会话凭据、HTTP 请求、响应 envelope 解析、响应大小上限和身份代次复核,React `llmModelCatalog` 在 Tauri 中只通过 typed invoke 取得目录快照;无 native host 时明确报告本地模型服务不可用,不回退到 React HTTP。该闭环不覆盖账户、素材直传、错误上报或发行网络,不能据此宣称全部 React 网络 I/O 已归 Rust。 + +本轮又完成发行网络闭环:`game_distribution_publish.rs` 从 Rust `platform_session` 读取当前 user/token/origin,在 Rust 内完成发布灰度、资料建议、封面定价/生成及异步任务收口、创建游戏/版本、分片续传和送审;`gameDistributionPublish.ts` 只保留 typed `invoke` façade,不再 import `requestClientApi` / `fetchClientHttp`、读取 token 或拼接远端 URL。封面队列由 Rust 统一做有界轮询,React 静止时不再按 1.6 秒访问远端任务;账户刷新、素材上传、错误上报和其它 clientApi 链路仍未迁移。 +本文件的离线前端规则是目标合同,不能据此宣称当前代码已全部满足。2026-09-23 已将项目创建目录与最近工作区偏好迁到 Tauri Rust AppData JSON、typed command 和变更事件;发送前提醒偏好已在 2026-09-24 迁到同一份 Rust 客户端偏好(`set_chat_prompt_polish_reminder_disabled` + 偏好事件);素材上传、错误报告与账户/钱包也已改为 Rust typed command(`upload_platform_media_asset`、`submit_error_report`、`account_api` 五条命令),渲染层不再持有 token、拼远端 URL 或发平台请求。2026-09-24 已完成最后一段:登录、验证码、refresh、登出与开发服务器选择迁到 Rust `auth_session`(AppData 私有 `client-session.json` 持有 refresh 凭据,登录/续期/登出后 Rust 自己安装本机运行时会话并发出状态事件);渲染层 `services/clientApi.ts` 删除、`clientHttp.ts` 收敛为 origin 校验与渠道默认值,`src` 内不再有 `fetch(` 调用、也不再读写 access token 或 refresh cookie。账户钱包、素材上传、错误报告、模型目录、发行与工作区偏好同样已改为 Rust typed command。Direct 回合保活也已归 Rust:回合登记时启动保活任务(按 access token 签发时间自助续期),回合结束即停止,渲染层不再持有任何业务定时器。仍未完成的是运行时验收:真实账号登录/续期/登出、微信支付与多窗口并发刷新。迁移必须保留账号/origin 隔离、幂等请求身份、失败关闭与既有数据恢复,不能通过增加一个任意 URL 的 HTTP IPC 代理伪装完成。 + +优先消除能在本地重复验证的请求放大:事件订阅必须在页面卸载和迟到 bootstrap 时同时释放前端监听与 Rust subscriber;持久化失败不得由 `setState → effect` 自触发无限重写;活动回合、本地生成任务和插件状态使用事件变化通知与启动快照,静止时不按周期读列表。正式状态仍以 Rust 注册表/账本为准,重复通知合并为一次在途读取和最多一次补读,旧作用域结果不能覆盖新项目。订阅不可用或首次读取失败必须明确报告可观察性失败,不能伪造业务终态。 + +低频离散状态使用事件即可,高吞吐流采用有界 channel 或已有 subscribe/consume 队列;二者都必须有订阅释放、初始快照、顺序/代次隔离和有界积压。显示耗时、验证码倒计时、动画和长按交互属于短暂 UI 状态,不与业务轮询混淆。只有上游没有推送能力时,才允许由 Rust 统一管理有界、可取消的轮询。 + +验证包含:静止窗口的业务读取计数、重复挂载/卸载后的 Rust subscriber 数、失败写入调用次数上界、通知并发单飞、旧项目/迟到响应隔离。真实交互时延须区分用户动作到本地反馈、IPC 等待、Rust 执行和远端网络耗时,未实测不得给出“几百毫秒已消除”的结论。 + ### 缺少 AGC application facade +账户素材库快照和图片预览由 Rust typed command 提供:read_editor_asset_library 只返回稳定 assetId、文件夹与展示元数据,read_editor_asset_preview 在 Rust 内完成当前账号解析、换签、有界下载、图片 magic/重定向/session 校验并返回 data URL。AssetImporter/ImageImporterPreview 不请求素材库或 read-url,也不把签名地址交给 WebView。远程导入只提交 assetId 列表和现有 policy/requirements,由 Rust 重新解析权威素材、下载并登记;预览字节不作为导入事实。React 切换素材、项目或卸载后忽略旧预览结果。 能力散落在 `agent`、`editor_project.rs`、`external_editor_api.rs`、`ai_tasks.rs`、快照路由和生成队列中。它们各自可用,但调用方难以判断一项用户意图应该走本地 Run、云端 task 还是外部 generation operation。 **整理方向**:先建立逻辑 facade 和 capability catalog,保留现有路由作为 adapter;只有当两个以上入口共享同一业务流程时,才下沉 application service。 diff --git a/docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md b/docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md index d454023b5..a7a3f716e 100644 --- a/docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md +++ b/docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md @@ -101,7 +101,7 @@ templates/ | --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `fetch_game_template_library` | 读 `templates/index.json`(≤4 MiB),校验后缓存到 `/templates/index.json`;网络失败时回退本机缓存并在 `source` 标 `cache`。远端已经答话但正文不是合法 UTF-8 或不符合 schema、以及缓存自己损坏时,一律失败关闭,不用缓存掩盖远端错误 | | `download_game_template` | 取清单里对应条目,流式下载 zip(≤512 MiB),校验字节数与 SHA-256,解压到 `/templates/installed///`,最后写 `installed.json` 作为安装完成的唯一标记 | -| `create_automatic_local_game_project_from_template` | 需要时先安装模板,然后在自动工作区根目录下按既有自动工作区规则建目录:先复制模板文件;Cocos 项目更新自身身份后走既有 Cocos 导入,Godot 项目改写工程显示名后走既有 Godot 导入,其余沿现有 `init_local_game_project_at` 初始化。根目录默认是 `/projects/`,用户可选 `projectsRoot` 覆盖(必须来自本机目录选择器并通过私有路径门禁),见 [`【实施计划】AGC项目创建目录可选-2026-09-17.md`](../project-memory/plans/【实施计划】AGC项目创建目录可选-2026-09-17.md) | +| `create_automatic_local_game_project_from_template` | 需要时先安装模板,然后在自动工作区根目录下按既有自动工作区规则建目录:先复制模板文件;Cocos 项目更新自身身份后走既有 Cocos 导入,Godot 项目改写工程显示名后走既有 Godot 导入,其余沿现有 `init_local_game_project_at` 初始化。根目录默认是 `/projects/`;用户在设置「工作区」里改选的创建目录由 Rust 客户端偏好(`workspace-preferences.json`)持有,建项时由 Rust 读取并执行同一套私有路径门禁(非空绝对路径、普通目录、拒绝链接与 reparse point、user-selected 一次性修复) | 安全与健壮性: diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index 42567d8ca..e9f299940 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -1390,7 +1390,8 @@ game-project/ ## 2026-08-20 Direct Codex 审核 Skill Pack 与受控工具内核 - 普通项目对话由一个 project-bound Codex app-server thread 执行。客户端系统提示词包含最小工程合同、项目 prompts 和审核 Skill 索引;源码与 Skill 正文按任务需要读取。提示词、工具描述与 Skill 直接描述当前任务、输入和成功条件,细节按调用需要提供。 -- 首页提供“做游戏 / 做素材 / 做方案”三个创作类型,默认“做游戏”。每次首页提交自动创建一个新项目并进入项目工作台。用户正文原样进入项目对话,`game|art|doc` 作为受限结构化首轮上下文传给同一 Codex thread。 +- 首页提供“做游戏 / 做方案”两个创作类型(`game` / `doc`),默认“做游戏”;“做素材”入口已退役,素材生成在项目内按实际工作流触发。每次首页提交自动创建一个新项目并进入项目工作台。用户正文原样进入项目对话,`game|doc` 作为受限结构化首轮上下文传给同一 Codex thread;持久草稿里遗留的 `art` 按 `game` 处理(`effectiveCreationType` 映射),不再产生第三种首轮上下文。 +- 「策划补全」是“做游戏”专属的提交前勾选(2026-09-15 起):勾选时该档提交 `planning`,未勾选时提交 `direct-build`;“做方案”始终走立项策划链路,与本勾选无关。复选框只在“做游戏”档渲染;切换创作类型时首页表面整体重挂,勾选状态随之清除,切回来必须是未勾选——这条可观察契约由 `appSurface` 的「scopes the 策划补全 option to the game entry」与「submits the game entry with planning when 策划补全 is checked」两条用例钉住,实现侧不额外维护重置逻辑。 - `agc-skill-pack.v1` 包含完整游戏交付流程、项目结构、陶泥儿美术、Web 游戏实现、真实浏览器试玩、客户端资源投影,以及 Unity/Godot 编辑器常用操作八项审核 Skill。清单记录用途、触发条件、所需工具、版本和内容 SHA-256;审核文本按 UTF-8 读取并将 CRLF 规范为 LF 后计算指纹和安装,避免混合换行造成 Windows / Linux 构建结果漂移,语义内容变化时必须同步重算对应清单指纹并提升版本。同步统一运行 `npm run agc:skill-pack:sync`,只读校验由 AGC `typecheck` 和 release build 自动执行,发现漂移时直接列出 Skill 与实际摘要,不让失配内容进入构建产物。客户端把审核文件安装到隔离目录后通过 app-server `skills/extraRoots/set + skills/list` 注册并复核,完整正文由 Codex 原生 Skill 机制按意图加载,一层引用只能经 `agc_read_skill_resource` 读取清单内 Markdown。引用路径按平台无关规则拒绝反斜杠、盘符、UNC、绝对路径和 `..`,不能依赖当前宿主的 `std::path` 语义判断其它平台路径。 - DirectProject 连接客户端内置的 `agc_tools` STDIO MCP,并在启动时接入客户端扩展仓库中用户已启用的独立第三方 STDIO/HTTP MCP 配置。内置工具包括审核引用读取、图片生成、标准陶泥儿美术准备、已登记资源有界查询、视频 / 角色动画 / 音效 / BGM 的 create-or-derive 语义生成、已登记图片去背景、desktop/mobile 浏览器试玩和受控 `agc_web_search`。内置 MCP 进程负责协议;真实浏览器、付费平台调用与受控搜索通过随机 loopback 地址回到客户端主进程,GUI 登录态、开发者 Key、项目路径、revision、operation 与幂等键由客户端持有并隔离于模型上下文。内置与用户启用的第三方 MCP 工具沿用 DirectProject 自动批准方式;付费资源工具由客户端绑定稳定回合身份、串行执行并优先恢复匹配账本。`llm.webSearchEnabled` 控制 DirectProject 的 AGC 受控搜索工具暴露与执行。原生工具与审批权限以下方“DirectProject Codex 完整访问覆盖”为准。 - 陶泥儿生成复用持久幂等账本、operation 恢复、来源/下载/PNG 解码和 manifest 登记;普通客户端使用当前 AGC 登录会话及账号路由,受控的 ExternalDeveloper 发布模式在客户端内部使用按服务器 origin 隔离的私有 Key。凭据失效、来源不明或结果未知时失败关闭,不能自动换 Key 或重新扣费。 @@ -1569,6 +1570,8 @@ DirectProject、Agent Runtime、Provider、app-server、内置 MCP、命令执 项目内统一落库目录为 `.agent/runtime/errors/`,事件记录采用幂等 JSONL 或 JSON sidecar;写入失败不能覆盖原始业务错误,但必须在事件中标记 `persistenceFailed`。DirectProject 对话历史必须持久化本轮用户消息、终态错误的安全 assistant 投影和诊断引用,使下一轮能够读取上一轮失败证据。前端只展示 `publicText`,点击详情后按 `detailRef` 读取有界、脱敏的诊断,不直接展示私有 `detail`。 +前端取回 `detailRef` 的口径是失败文案末尾的固定后缀「;详情:」:Rust 侧 `direct_codex_failure_text_keeps_the_detail_ref_marker_for_the_renderer` 与前端 `tests/agentRuntimeErrorDetail.test.ts` 各自钉住同一份文案形状与它的解析,任一侧改文案或改解析都会变红。失败提示只展示映射后的安全 `publicText`(v1 历史形状与 v2 现行形状都映射成「阶段 + 摘要 + 建议 + 是否可直接重试」),诊断正文不在提示里预读、也不写入历史投影,而是由聊天状态栏下方的「查看详情」入口按需调用只读命令读取并二次脱敏;这条交互由 `tests/appSurface/chat-composer.suite.ts` 的「失败提示保留可执行原因,诊断正文只在「查看详情」时读取」与 `tests/agentRuntimeModel.test.ts` 的 v2 映射用例钉住,渲染层仍不参与错误分类。 + `turn/completed` 等待超时必须区分 `idle-timeout`、`hard-timeout`、`transport-closed`、`failed-turn`、`invalid-terminal` 和 `tool-error`;收到内置工具参数错误后必须结束当前工具调用并进入可行动终态,不能继续使用越界的试玩 `attempt` 或无限等待。试玩次数由客户端按当前 `clientTurnId` 持久化分配,模型不能自由递增;超过上限必须返回一次终态并停止回合。 游戏素材完成门必须扫描实际参与构建的 `game/` 源码模块,读取 manifest 的登记身份与相对路径,并把构建后的 URL 映射回登记身份。固定素材路径只能作为兼容候选,不能作为唯一准入。已登记且被真实源码引用、被构建纳入并在浏览器证据中观察到的资源通过;未登记、来源不匹配或只存在于设计规范中的资源继续失败关闭。 @@ -1675,6 +1678,22 @@ Direct 回合的所有权属于进程内项目身份锁,不属于当前页面 - 运行时 smoke:AGC 开发态打开项目、观察索引写入与同步日志、关闭工作区窗口后确认关闭触发的那次同步执行;报告为"客户端 diff 已验证 / 服务端已配置环境联调"两层,不合并成一句"已通"。 - 边界:新增日志与错误文案不含 Access Token、AccessKey、绝对路径与项目内容。 +| 验收面 | 对应证据 | +| --- | --- | +| 首次全量、单文件改动、删除与摘要复用 | `project_snapshot_diff_reuses_metadata_and_reports_a_single_modification`、`project_snapshot_diff_treats_touched_but_identical_content_as_metadata_only`、`project_snapshot_manifest_metadata_changes_sync_without_content_changes` | +| 排除口径与 `.agent` 整目录上传 | `project_snapshot_scan_skips_excluded_paths_and_oversized_files`、`project_snapshot_scan_uploads_whole_agent_directory`、`project_snapshot_sync_policy_keeps_agent_state_and_still_blocks_credentials` | +| 单次预算、延后与失败文件不推进索引 | `project_snapshot_diff_defers_files_over_the_sync_budget`、`project_snapshot_synced_files_exclude_failed_and_deferred_paths`、`project_snapshot_pending_files_include_every_unsynced_path_once` | +| 幂等跳过与确定性鉴权失败停止 | `project_snapshot_upload_marks_remote_duplicates_and_sends_marker_headers`、`project_snapshot_upload_stops_after_a_deterministic_authentication_failure` | +| 同步期间被改写的文件不上传也不推进索引 | `project_snapshot_diff_defers_files_that_changed_while_being_read`、`project_snapshot_upload_skips_files_that_changed_after_the_diff` | +| 同项目串行化、周期触发让位与退出等待 | `project_snapshot_sync_is_serialized_per_project`、`project_snapshot_periodic_trigger_yields_while_a_sync_is_in_flight`、`project_snapshot_exit_wait_includes_scheduled_tasks_waiting_for_the_project_lock` | +| 单窗口生命周期登记与项目身份校验 | `project_snapshot_workspace_lifecycle_tracks_the_single_client_window`、`project_snapshot_independent_window_url_supplies_a_fallback_project`、`project_snapshot_project_id_validation_rejects_paths_and_unsafe_values` | +| 索引往返、损坏恢复与旧清单完整性未知 | `project_snapshot_index_round_trips_and_recovers_from_corruption`、`project_snapshot_legacy_index_keeps_completeness_unknown` | +| 远端回收只删上一版登记过的对象、读不到上一版一张不删、单轮有上限 | `project_snapshot_reclamation_retires_only_objects_the_previous_manifest_registered`、`project_snapshot_reclamation_deletes_nothing_without_a_readable_previous_manifest`、`project_snapshot_reclamation_is_bounded_per_manifest_write` | +| 服务端校验、413 与 429、渠道失败关闭 | `project_snapshot_manifest_rejects_duplicates_and_out_of_range_values`、`project_snapshot_manifest_rejects_too_many_entries`、`project_snapshot_manifest_rejects_a_project_over_the_total_cap`、`project_snapshots_upload_accepts_empty_files_and_rejects_false_checksums`、`project_snapshot_user_quota_stops_after_the_hourly_file_limit`、`project_snapshot_channel_fails_closed_on_invalid_configuration` | +| 真实 OSS 往返 | `project_snapshot_live_sync_uploads_once_then_reports_no_op`(默认忽略,需要 `GENARRATIVE_AGC_PROJECT_SNAPSHOT_LIVE_PROJECT` 与真实 api-server / OSS 凭据) | + +本轮定向证据:客户端 `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml project_snapshot -- --test-threads=1` 为 24 passed / 1 ignored;服务端 `cargo test -p api-server project_snapshot -- --test-threads=1` 为 21 passed / 1 ignored。真实 OSS 往返、开发态打开项目的索引写入与关窗触发仍属运行时 smoke,未在本轮取得证据。 + ### 后台工程列表与下载 - 正式客户端在单窗口内切换启动器和项目,不以窗口 URL 判断活动项目。前端把当前窗口的已打开项目登记给原生同步器;打开后发起首轮同步,离开/切换项目和物理关窗为旧项目补同步,周期扫描只读这份窗口登记。重复登记同一路径不重复发起;注册失败写诊断,不能假装已登记。 diff --git a/docs/technical/【技术方案】DirectProject Codex原始历史与异常恢复-2026-09-04.md b/docs/technical/【技术方案】DirectProject Codex原始历史与异常恢复-2026-09-04.md index e84383e00..dfbe46596 100644 --- a/docs/technical/【技术方案】DirectProject Codex原始历史与异常恢复-2026-09-04.md +++ b/docs/technical/【技术方案】DirectProject Codex原始历史与异常恢复-2026-09-04.md @@ -157,3 +157,20 @@ subscriber 不依赖 `unsubscribe` 或传输层断开清理。每次 `subscribe` `subscribe` 必须在同一个 Thread Manager 边界注册 subscriber、捕获 queue 尾部、确定历史锚点和当前运行态事件;bootstrap 期间产生的新事件由该 subscriber 的内部 cursor 继续通过 `consume` 获取,不能丢失。 断线恢复优先调用 `consume(subscriptionId)`。subscription 仍有效时只返回该 subscriber 尚未消费的 queue 事件;subscription 已过期或 Thread Manager 重启后统一走新的 `subscribe`,再由前端按 `lastCompletedItemId` 从历史懒加载。Rust 不提供 `getItemSnapshot(itemId)`,已完成 item 始终通过历史读取。 + +### 钉住本节的用例(2026-09-24 复核) + +本节的行为由以下用例守住;改动 Thread Manager 时按同一清单复核: + +| 契约 | 用例 | +| --- | --- | +| 多 subscriber 各自游标、互不推进 | `direct_thread_manager::tests::subscribers_have_independent_cursors_on_one_global_queue` | +| 逻辑队头回收与落后订阅过期 | `queue_cleanup_only_removes_a_cleanable_prefix`、`slow_subscriber_is_expired_when_queue_limit_is_reached` | +| 完成事件只在 item 持久化后入队 | `completion_releases_item_events_only_after_the_completion_event_is_appended` | +| 生命周期锚点独立于 replay 队列 | `turn_completed_anchor_survives_empty_queue_for_new_subscriber`、`bootstrap_contains_lifecycle_anchor_and_unfinished_events_only` | +| 未完成 item 从 opener 起可重放、未决审批保留 | `bootstrap_replays_opener_user_item_id`、`unresolved_approval_is_kept_in_bootstrap_until_resolved` | +| 订阅释放幂等且能回收队头 | `unsubscribe_releases_the_subscriber_and_is_idempotent`、`unsubscribe_allows_a_cleanable_prefix_to_be_trimmed` | +| legacy 历史行失败关闭(不 fallback、不迁移) | `direct_project_history_item_from_parsed_line` 对非 canonical `type` 直接报错;见 `direct_project_history` 定向用例 | +| 前端按 `subscriptionId` 唤醒并处理回执竞态 | `apps/ai-game-creator-shell/tests/directThreadChatSubscription.test.tsx` | + +运行时验收(关闭/切页后重进、并发 item、短暂断线 consume、过期重订阅)仍需真实客户端执行;自动化只覆盖到此表为止。 diff --git a/docs/technical/【技术方案】DirectProject本轮附件路径映射-2026-08-31.md b/docs/technical/【技术方案】DirectProject本轮附件路径映射-2026-08-31.md index c5143ff8d..c7e1de80c 100644 --- a/docs/technical/【技术方案】DirectProject本轮附件路径映射-2026-08-31.md +++ b/docs/technical/【技术方案】DirectProject本轮附件路径映射-2026-08-31.md @@ -122,7 +122,7 @@ Project 头与行(禁止出现 GDD / 规格 / 权威 / 必须读取): ### 3.3 谁渲染、谁看见 - sidecar **只在进 Codex 前由 Rust 拼装**。 -- `.agent/conversations/project.jsonl` 继续写用户原文(现有 `append_local_conversation_message`)。 +- `.agent/conversations/project.jsonl` 继续由 Rust Direct/Design coordinator 写入用户原文;React 渲染层只保留当前页面投影,不再通过通用 `append_local_conversation_message` 追加聊天行。 - 工作台气泡继续显示 latch / 输入框原文,不把 sidecar 画进 UI。 - 未完成首轮的 hydration 重放目前只带 prompt:本期不把附件写进 jsonl,进程重启后的未完成首轮可能丢映射。完整成功首轮不受影响。不为此新增会话 schema。 diff --git a/docs/technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md b/docs/technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md index ecbb3008a..eb6aec495 100644 --- a/docs/technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md +++ b/docs/technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md @@ -122,7 +122,7 @@ Runtime 不维护文档版本号,不解析文档版本,不提供版本回退 **交付结果**:策划 Agent 对话复用 GameAgent 的模型、推理档选择控件及配置通道,用户的新选择对后续策划回合实际生效,并保持 GameAgent 原有行为兼容。 -本节是本次变更的唯一主规范。控件接入已完成并提交,运行时模型生效逻辑已实现、待验收。拆分与验收见 [控件接入里程碑](../project-memory/plans/【里程碑】策划Agent模型与推理档控件接入-2026-09-20.md) 和 [模型生效里程碑](../project-memory/plans/【里程碑】策划Agent回合模型选择生效-2026-09-20.md)。 +本节是本次变更的唯一主规范。控件接入已完成并验收(对应开发期里程碑与实施计划已归档删除,结论以本节为准);运行时模型生效逻辑已实现、待验收,见 [模型生效里程碑](../project-memory/plans/【里程碑】策划Agent回合模型选择生效-2026-09-20.md)。 #### 范围与非目标 diff --git a/docs/technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md b/docs/technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md index 7b09b265e..4ebc408c5 100644 --- a/docs/technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md +++ b/docs/technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md @@ -209,7 +209,7 @@ cargo test -p spacetime-module web_project --manifest-path server-rs/Cargo.toml ```bash npm run test -- src/services/sseStream.test.ts -npm run test -- src/components/editor/agent +npm run test -- src/services/image-editor/editorAgentClient.test.ts # 2026-09-24 修订:`src/components/editor/agent` 已随旧创作链路退役,现行画布 Agent 用例在 image-editor 目录 npm run typecheck npm run check:encoding git diff --check diff --git a/docs/【功能说明】AGC聊天素材引用-2026-09-08.md b/docs/【功能说明】AGC聊天素材引用-2026-09-08.md index fcff22137..2591f9d63 100644 --- a/docs/【功能说明】AGC聊天素材引用-2026-09-08.md +++ b/docs/【功能说明】AGC聊天素材引用-2026-09-08.md @@ -92,3 +92,31 @@ AGC 聊天输入框支持以结构化引用标记当前项目已登记素材, - 资源改名后引用芯片与候选列表的显示名自动刷新; - 切换 / 重开会话恢复草稿后光标落在文本末尾,引用按原 content 顺序恢复为 inline 芯片。 - Skill 提及按原 content 顺序恢复为 inline 芯片;未知、禁用或未发现 Skill 在发送前失败关闭,不写入历史、不启动回合。 + +## 钉住 canonical user item 的用例(2026-09-24 复核) + +本文第「提交时前端把 Lexical 草稿直接编码为受限 Response API user `message` item」一段的合同由以下用例守住: + +| 契约 | 用例 | +| --- | --- | +| 资源引用只带 camelCase `resourceId`,多余身份字段拒绝 | `direct_codex_user_item::model::tests::resource_reference_serializes_with_only_camel_case_resource_id`、`resource_reference_rejects_extra_identity_fields` | +| 未知 content part 失败关闭 | `model::tests::unknown_content_part_fails_closed` | +| 只看整条消息是否为空:空白片段合法,非文本 part 也算输入 | `validation::tests::only_all_blank_content_counts_as_empty_input`、`whitespace_parts_are_valid_next_to_meaningful_input`、`non_text_parts_always_count_as_input` | +| 正文不能绕过非法引用 | `wire::tests::nonempty_text_does_not_bypass_invalid_reference_validation` | +| 附件/Skill 引用数量独立有界、附件必须带项目路径、名称与媒体类型有界 | `validation::tests::inline_attachment_count_is_bounded_independently`、`inline_skill_reference_count_is_bounded_independently`、`imported_attachment_requires_a_project_path`、`attachment_name_and_media_type_are_bounded_and_well_formed` | +| 标准 `response_item` 原样通过,wire input 不含 AGC 私有 part,顺序不变 | `wire::tests::standard_response_item_passes_through_without_agc_private_parts`、`response_item_projection_uses_input_text_not_turn_input_text`、`attachment_parts_remain_in_canonical_order_when_projected` | +| legacy 历史行失败关闭(不 fallback、不迁移) | `wire::tests::history_item_without_type_fails_closed` | +| 草稿顺序、附件-only 输入与恢复 | `apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx` | +| ts-rs 绑定与 Rust 模型同步 | `model::export_bindings_directcodexuser*`(`cargo test direct_codex_user_item` 一并运行) | +## 钉住 Skill 提及的用例(2026-09-24 复核) + +`$skill-name` 提及(候选、原子 chip、canonical part、Codex wire 映射)由以下用例守住: + +| 契约 | 用例 | +| --- | --- | +| canonical part 只保存稳定 Skill 名,拒绝正文/路径/凭据类附加字段 | `direct_codex_user_item::model::tests::skill_reference_serializes_with_only_the_stable_name` | +| Skill 引用数量独立有界 | `direct_codex_user_item::validation::tests::inline_skill_reference_count_is_bounded_independently` | +| 目录里不存在(未启用 / 未发现)的 Skill 在启动回合前失败关闭,错误文案可指导重新选择 | `direct_codex_user_item::wire::tests::unavailable_skill_reference_fails_closed_before_any_turn_input` | +| 合法 Skill 映射成 Codex 原生 `{"type":"skill","name","path"}`,顺序与 canonical content 一致 | 同上用例的后半段、`agent::codex_app_server` 的 `direct_project_turn_input` Skill 用例 | +| `$` 候选懒加载、过滤、chip 原子性与 `$`/`@` 共存 | `apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx` | +| 无 Skill 的旧消息、素材引用与标准 `response_item` 行为不变 | `wire::tests::standard_response_item_passes_through_without_agc_private_parts` | \ No newline at end of file diff --git a/docs/【协作规范】文档生命周期与现状索引-2026-09-12.md b/docs/【协作规范】文档生命周期与现状索引-2026-09-12.md index 62302d25d..7d6f30a9e 100644 --- a/docs/【协作规范】文档生命周期与现状索引-2026-09-12.md +++ b/docs/【协作规范】文档生命周期与现状索引-2026-09-12.md @@ -75,13 +75,9 @@ ## 开放事项与活动计划 -当前 `open-todo`: +开放事项以 `docs/project-memory/todos/` 目录为唯一清单(不再在本文件手工维护子集):待办、待解决、待评估与目标适配类文件的当前状态以各自文件为准,其中 `【待办】计划收口剩余项索引-2026-09-24.md` 汇总了各计划仍未完成或未验收的条目。 -- `docs/project-memory/todos/【待解决】AI游戏创作高风险审批Rank-2026-07-20.md` -- `docs/project-memory/todos/【待评估】UI编辑器字体跨运行时像素一致性-2026-08-19.md` -- `docs/project-memory/todos/【已知问题】AppConfig与AppState调试输出敏感配置泄漏-Master遗留-2026-08-07.md` - -当前没有活动计划;新任务按 SDD 规则在 `docs/project-memory/plans/` 建立计划,完成、取消或合并后删除。 +活动计划同样以目录为唯一清单:`docs/project-memory/plans/` 下的 `【里程碑】` 与 `【实施计划】` 是开发期临时产物,完成、取消或合并后立即删除并把持久结论回写主规范或共享记忆;要求可见的未完成边界写在各自文件的「未验证」章节里。 ## 下一轮复核顺序 diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index 9df1a01d4..4c4c4fb3a 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -786,7 +786,7 @@ cat /var/lib/genarrative/health-patrol/status.json Jenkins Copy Artifact 必须保持 `Production` 权限模式;产物生产者要在 Jenkinsfile 中用 `copyArtifactPermission` 精确授权消费者,不能依赖 Migration 模式或全局 `Job/Read`。固定映射为 `Genarrative-Stdb-Module-Build` → `Genarrative-Stdb-Module-Publish`、`Genarrative-Api-Build` → `Genarrative-Api-Deploy`、`Genarrative-Web-Build` → `Genarrative-Web-Deploy`、`Genarrative-Database-Export` → `Genarrative-Database-Import`、`Genarrative-Agc-Global-Version-Issue` → `Genarrative-Scheduled-Revision-Trigger` / `Genarrative-Scheduled-Release-Trigger`(发号 Job 必须授权两条调度器读取 `agc-global-version.txt`;缺这条会让整轮调度在发号之后失败——号已烧、渠道构建没被触发,2026-09-20 #103 即为此)。如果 `copyArtifacts` 报 `Unable to find project for artifact copy`,但来源 Job、指定构建号和归档都实际存在,先检查来源 Job 的 `CopyArtifactPermissionProperty`;修复 Jenkinsfile 后必须先运行一次产物生产者,让 Declarative Pipeline 把 Job property 写回 Jenkins,再重跑 Deploy / Publish / Import。`npm run check:production-ops` 会防止这些 Copy Artifact 授权再次丢失。 -`Genarrative-Web-Build` 先通过 `scripts/jenkins-prepare-npm-env.sh` 在 Jenkins 运行用户的持久版本目录准备 npm `10.9.7`,显式提升该 `bin` 后校验真实版本,不依赖系统 `/usr/bin/npm` 或 `packageManager` 声明自动切版。在运行根 Vitest 前必须按唯一根 `package-lock.json` 执行一次干净的 `npm ci`。根 lock 聚合全部 workspace,因此会安装 AI 游戏创作壳合法声明的 `@tauri-apps/api`、`@tauri-apps/plugin-http` 等 Tauri guest;这些依赖仍只归属 AGC workspace,不得加入根 H5 或 Desktop manifest。排查收集失败时先运行 `npm run check:npm-workspaces` 并核对根 lock 的 workspace entry,禁止恢复第二份 lock 或子目录安装。 +`Genarrative-Web-Build` 先通过 `scripts/jenkins-prepare-npm-env.sh` 在 Jenkins 运行用户的持久版本目录准备 npm `10.9.7`,显式提升该 `bin` 后校验真实版本,不依赖系统 `/usr/bin/npm` 或 `packageManager` 声明自动切版。在运行根 Vitest 前必须按唯一根 `package-lock.json` 执行一次干净的 `npm ci`。根 lock 聚合全部 workspace,因此会安装 AI 游戏创作壳合法声明的 `@tauri-apps/api`、`@tauri-apps/plugin-clipboard-manager` 等 Tauri guest(2026-09-24 起渲染层已无 HTTP 通道,`@tauri-apps/plugin-http` 随该通道一起从 AGC manifest 与根 lock 删除);这些依赖仍只归属 AGC workspace,不得加入根 H5 或 Desktop manifest。排查收集失败时先运行 `npm run check:npm-workspaces` 并核对根 lock 的 workspace entry,禁止恢复第二份 lock 或子目录安装。 `Genarrative-Web-Build` 会把 `build//web.tar.gz`、`web.tar.gz.sha256`、`release-manifest.json` 和 `scripts/deploy/production-web-deploy.sh` 直接归档为 Jenkins 构建产物;`Genarrative-Web-Deploy` 只通过 `copyArtifacts` 从指定上游构建复制这些产物和部署脚本,不再在目标机器 checkout Git,再执行随构建归档的 `scripts/deploy/production-web-deploy.sh`。Web 发布不再读取构建机本地缓存目录,也不再通过 release agent `rsync` 回构建机拉取大包;如果 deploy 找不到 `web.tar.gz`,应先检查上游 Web Build 是否按同一 `BUILD_VERSION` 成功归档产物。 diff --git a/docs/【技术方案】AGC异步操作可恢复闭环-2026-09-14.md b/docs/【技术方案】AGC异步操作可恢复闭环-2026-09-14.md index fe08886e7..68b876ad5 100644 --- a/docs/【技术方案】AGC异步操作可恢复闭环-2026-09-14.md +++ b/docs/【技术方案】AGC异步操作可恢复闭环-2026-09-14.md @@ -2,6 +2,8 @@ 更新时间:`2026-09-14` +> 2026-09-24 更正:首页「做素材」创作类型已于 2026-09-16 退役,现役创作入口只有「做游戏 / 做方案」两个(素材生成在项目内按实际资源工作流触发)。本文涉及「做游戏 / 做素材 / 做方案」三入口的表述请按此口径理解,其余结论不变。 + ## 目标 让 AGC 的认证、最近项目检查和首页自动创建在响应体卡住、单目录慢、页面切换或操作迟到时仍然可观察、可重试且不会重复创建或覆盖当前项目。