文档:记录 AGC 测试类型门禁与 Node 环境口径
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 5m15s
Project CI / Backend tests (pull_request) Failing after 23s
Project CI / AI game creator shell Rust crates (pull_request) Failing after 2m47s
Project CI / Repository checks (pull_request) Failing after 38s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m20s
Project CI / Frontend tests (pull_request) Successful in 2m38s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m12s
Project CI / Native shell tests (pull_request) Successful in 6m52s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 5m15s
Project CI / Backend tests (pull_request) Failing after 23s
Project CI / AI game creator shell Rust crates (pull_request) Failing after 2m47s
Project CI / Repository checks (pull_request) Failing after 38s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m20s
Project CI / Frontend tests (pull_request) Successful in 2m38s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m12s
Project CI / Native shell tests (pull_request) Successful in 6m52s
- development-workflow 增补 AGC 测试类型门禁一节 - pitfalls 记录测试未进 tsconfig 时类型断言为空写的经验 - pitfalls 记录 Node 24+ Web Storage 顶掉 jsdom localStorage 的环境口径
This commit is contained in:
@@ -119,3 +119,7 @@ Gitea 缓存部署必须区分网络:runner 的 RPC 走 `gitea-runner-fetch-ga
|
||||
AGC Rust 两条 lane、crates、smoke、Backend 和桌面壳测试使用镜像内可信 sccache 对象快照;Native shell release step 显式清空双 wrapper,前端/repository checks 不启用。仅首次人工 bootstrap 时,维护者通过 `scripts/build-gitea-rust-cache.sh` 从远端 master 在限额、无宿主挂载的临时容器中按实际 cwd/profile/目标预热全部测试组,仅编译、不执行测试/应用;后端 workspace 与 spacetime-module 保持独立,AGC 的三个 cwd 入口之间清理预热 target,防止 fresh 判断漏产缓存键。最终镜像只追加 sccache、对象和来源元数据,不包含源码或 target。容量上限 4 GiB,不替代宿主旧镜像/归档清理。PR 只写当前容器层、不回传,不开放 Docker API/发布权限;继续禁用 incremental。`ci-rust-cache.sh` 在快照缺失、工具链不符或 wrapper 探测失败时直接编译,并隔离远程缓存配置和 daemon。分片日志记录编译耗时,收尾输出命中统计;两个 lane 的测试和前置检查不同,耗时差不是严格 A/B。线上存在活跃 CI 时不得重启 runner 或切换标签;全组启用前须刷新完整快照并逐组验证,详见开发运维文档。
|
||||
|
||||
`.gitea/workflows/project-ci.yml` 的客户端门禁拆成 lane 与功能 job,每个 job 只预热自己会构建的那几份依赖:`AI game creator shell Rust lane 1/2`、`lane 2/2` 各自预取一次 AGC 壳 manifest,并顺序运行两片 Rust bin 单测;`AI game creator shell Rust smoke` 同样只预取 AGC 壳 manifest(`agent-run` smoke 会用 `src-tauri/Cargo.toml` spawn `cargo run`),`AI game creator shell Rust crates` 预取 `server-rs/Cargo.toml` 与独立 crate,`Native shell tests` 预取桌面壳与 AGC 壳 manifest,`AI game creator shell web tests` 不触碰 Cargo,不预热。两条 Rust lane 与 smoke job 必须在编译前通过 `scripts/ci-npm-ci-with-retry.sh` 执行根 `npm ci`:AGC 壳的 `build.rs` 会从 `node_modules` 准备 Claude Agent SDK 与目标平台原生运行时,镜像中的 npm 下载缓存不能替代安装。人工 `scripts/build-gitea-rust-cache.sh` bootstrap 同样在首次编译 AGC 壳前安装 npm 依赖;只有不构建壳的 crates job 继续省略 npm 安装。两个被 `server-rs/Cargo.toml` 排除、且没有提交 `Cargo.lock` 的独立 crate(`agent-runtime-core`、`agent-runtime-orchestration`)只能在 `AI game creator shell Rust crates` 里用不带锁标志的 fetch。AGC 壳的 bin target 单测(约 2466 条)由 `apps/ai-game-creator-shell/scripts/run-rust-shell-test-shards.mjs` 编译后按 `--list` 名单分 4 片:每次分片调用用 `--shard-index=<i>` 只跑自己那片,片内保持 `--test-threads=1` 并使用独立 `TMPDIR`;两条 lane 之间并发,lane 内顺序运行两片,避免重复依赖预热和同一容器内多进程争抢。不要改回「一个 job 内多进程并行这几片」——同一容器里它们会争抢共享 `HOME`、target 目录与固定临时路径,实测比整套串行还慢。每个分片调用都会自校验「片并集等于全集且互斥」,因此改分片规则不会静默漏跑。Backend host workspace tests 使用 `cargo test --locked --workspace --exclude spacetime-module --no-fail-fast`,避免 `spacetime-module` 的 `spacetime-types` feature 统一污染普通领域 crate 的 host 测试;随后单独执行 `cargo test --locked -p spacetime-module --no-fail-fast`,由 `spacetime-module/src/active.rs` 在 host 测试构建期间提供仅测试期的 SpacetimeDB ABI 链接支持,使该 crate 的纯单元测试也纳入 Backend 门禁。`spacetime-module` 的 reducer / procedure 运行时行为仍必须通过真实 SpacetimeDB runtime/integration harness 验证,host 链接支持不得被当作运行时替身。Backend 另外执行 `cargo check --locked -p spacetime-module` 验证模块源码。AGC 壳检查还会运行 `platform-llm` 与 `shared-contracts` 的 server-rs workspace 测试,这些命令以及 AGC 壳测试必须带 `--locked`,避免在测试阶段重新解析 registry index;锁文件发生变化时应先更新受信任 CI 镜像缓存,再重跑门禁。
|
||||
|
||||
## AGC 测试类型门禁
|
||||
|
||||
AGC 测试(`apps/ai-game-creator-shell/tests/`)与生产 `src/` 同受类型门禁。`apps/ai-game-creator-shell/tsconfig.tests.json` 以 `include: ["src", "tests", "vite.config.ts"]`、`types: ["vite/client", "vitest/globals"]`、`allowImportingTsExtensions`、`allowJs` 全量覆盖:新增测试文件自动纳入,不存在基线、豁免名单或 `@ts-nocheck`。入口 `npm --prefix apps/ai-game-creator-shell run check:tests:types`(`tsc -p tsconfig.tests.json --noEmit`)已并入该 app 的 `typecheck`,因此 `npm run agc:typecheck`、`npm run ai-game-creator-shell:check:web` 与 CI 的 `AI game creator shell web tests` 都会执行。修测试只做类型层改动,不改断言与行为;禁止 `@ts-ignore`、`as any`,仅当 mock 泛型函数确实不可兼容时才允许带中文注释的 `as unknown as`。
|
||||
|
||||
@@ -6284,3 +6284,14 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
- **诊断口径**:`agent.direct_turn.host_dropped` / `agent.direct_turn.panic` 里的令牌字段必须写 `tt=`,写 `turnToken=` 会命中脱敏标记,整行变成 `<sensitive diagnostic details redacted>`,离线只剩"说不出原因"的 HostDropped。
|
||||
- **验证**:dev 栈里用 CDP 注入真实回合(`node %TEMP%\agc-cdp.mjs <expr>`):①读文件轮 `claude-parse-done chars=108`,`.agent/conversations/project.jsonl` 出现 `direct-codex:cdp-…:assistant` 条目,回复内容与 `game/index.html` 前两行(`<!doctype html>` / `<html lang="zh-CN">`)逐字一致(证明宿主工具真的执行了);②聊天视图打开时注入 `只回三个字:收到了`,DOM 断言(`document.body.innerText`)同时出现用户气泡 `11:40:05`、助手回复 `收到了` 与 `本轮结束于 11:40:16 · 耗时 10.7秒`(证明 `item.completed` 实时投影生效,不必重进项目);同一日志不再出现新的 `host_dropped`。另有 `agent::claude_code_cli::tests::direct_claude_feedback_reply_does_not_fail_on_a_reused_client_turn_id` 回归覆盖同一回合两次不同回复。`cargo test … -- claude_code_cli::tests direct_turn_failure::tests` 19 passed。
|
||||
- **关联**:`apps/ai-game-creator-shell/src-tauri/src/agent/thread_manager/dispatch.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/direct_turn_failure.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/claude_code_cli.rs`、`apps/ai-game-creator-shell/agent-sidecar/src/index.mjs`。
|
||||
|
||||
## 2026-10-03 AGC 测试不在任何 tsconfig 里时,`satisfies` / `vi.fn<(...)>` 这类类型断言是空写
|
||||
|
||||
- **现象**:`apps/ai-game-creator-shell/tests/` 从未进过任何 tsconfig,vitest 0.34 用 esbuild 转译不做类型检查,`satisfies TurnFailure`、`vi.fn<(input: X) => void>()` 全部静默通过。把 tests 挂进 `tsconfig.tests.json` 后一次暴露 683 条既有错误(99 个文件、约 47% 的测试文件),单个文件最多 73 条。
|
||||
- **根因 1(配置缺口)**:app `tsconfig.json` 的 `include` 只有 `["src","vite.config.ts"]`;根 `typecheck` 只跑 `tsconfig.typecheck-guardrails.json` 的根 `src` 白名单;CI `agc-web` lane 只跑 vitest。三处都不覆盖 app tests。
|
||||
- **根因 2(vitest 0.34 口径)**:本仓库固定 `vitest@0.34.6`,其 `fn<TArgs extends any[], R>` 收的是**参数元组**;写成 vitest 1.x 习惯的 `vi.fn<(input: X) => void>()` 会把函数类型当作 `TArgs`,报 `TS2344`(constraint `any[]`)并连带 `TS7053`/`TS2493`。正确口径是 `vi.fn<[X], R>()` 或直接 `vi.fn(impl)`;`.mock.calls[0]` 在 `noUncheckedIndexedAccess` 下需要非空断言。
|
||||
- **根因 3(脚本 `.mjs`)**:测试 import `../scripts/*.mjs`,`allowJs: false` 报 `TS7016`;打开 `allowJs` 后 TS 按 JS 默认值推导出过窄签名(回调参数、`spawn`/`spawnSync` 重载、`never[]`、`null`),需要在测试里按运行时真实契约声明局部签名。
|
||||
- **根因 4(过期桩)**:62 条 `TS2339/TS2353/TS2739/TS2741` 是测试桩与当前真实类型脱节(字段被删除/改名/新增必填),例如 `setAgentChatProjectPath`、`conversationKey`、`runId`、`supervisor`→`chat`。
|
||||
- **现行口径**:见 `development-workflow.md` 的「AGC 测试类型门禁」;tests 必须 0 error,不引入基线或豁免,只改类型层。
|
||||
- **环境提示**:Node 24+ 默认启用实验性 Web Storage,全局 `localStorage` 未配置即 `undefined`,会顶掉 vitest 0.34 jsdom 环境里的 Storage,`recentProjectsHook.test.tsx`、`gameDistributionPublish.test.ts` 在 Node 26 上失败(HEAD 即如此)。项目按 `@types/node ^22.14` 面向 Node 22,本机用 fnm 装 v22.23.3 并设为 default(`~/.configure/profile.d/fnm.sh` 在 shell 启动时 `eval "$(fnm env)"`),Node 22 不暴露该全局、jsdom 的 localStorage 正常,仓库无需任何改动。不要用 `--localstorage-file=…` 绕:那只是把 Node 自己的文件型 Storage 顶上来,多个用例文件共享同一份状态。
|
||||
- **关联**:`apps/ai-game-creator-shell/tsconfig.tests.json`、`apps/ai-game-creator-shell/package.json`、`apps/ai-game-creator-shell/tests/`。
|
||||
|
||||
Reference in New Issue
Block a user