diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index bf30e4c85..6a39012a7 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -1,5 +1,13 @@ # 决策记录 +## 2026-10-04 CI 测试成功时静默(silent is gold) + +- 背景:`Frontend tests` 的 `npm run test:ci:frontend` 在成功 run 里仍回放被测代码的 console 输出——React `act(...)` 警告、`scripts/dev.test.ts` / `scripts/dev-all.test.ts` 的开发栈调度日志——把 CI 日志刷出大量与「红灯」无关的内容。 +- 决策:根 `vitest.config.ts` 固定 `test.silent: true`(`--silent` 的配置形态)。成功用例不再回放写进 stdout / stderr 的内容;reporter 仍输出每个文件一行进度与最终汇总,失败用例仍打印断言摘要与源码位置。`vitest.frontend-ci.config.ts` 通过 `mergeConfig` 继承该设置,AGC 与 repository checks 直接使用的根配置同样生效。本机排查用 `vitest run --silent=false` 覆盖。 +- 守护:`scripts/project-ci-workflow.test.ts` 新增用例钉住根配置的 `silent: true`,防止日后被顺手删掉。 +- 影响范围:`vitest.config.ts`、`scripts/project-ci-workflow.test.ts`、`docs/project-memory/shared-memory/development-workflow.md`、本文件。 +- 验证:`npx vitest run --config vitest.frontend-ci.config.ts`(243 files / 2761 passed,输出中 `stdout |` / `stderr |` 块与 `act(...)` 警告均为 0);定向 `scripts/{project-ci-workflow,dev,dev-all,dev-utils}.test.ts`(4 files / 114 passed);临时失败用例确认失败摘要仍打印;`--silent=false` 可恢复 console 输出;`git diff --check`、prettier、eslint `--max-warnings 0`(改动文件)通过。 + ## 2026-10-03 AGC 画布引用统一走「活跃聊天输入区」注册表(Issue 602) - 背景:画布的「引用」按钮与「拖拽批量引用」只派发 window 事件,消费者只有 `App.tsx` 一处,而它插的是绑在 `PlanningChatView` 上的 `chatComposerRef`;2026-09-22 DirectProject 拆分后普通项目走 `directProjectMode` 提前 return,渲染不到策划面 → ref 恒为 `null`,可选链静默吞掉点击(画布上是死按钮)。同一批合并冲突还丢了 `RESOURCE_REFERENCE_INSERT_MANY_EVENT` 的监听,批量引用连消费者都没有。 diff --git a/docs/project-memory/shared-memory/development-workflow.md b/docs/project-memory/shared-memory/development-workflow.md index c4e72194e..f241edbfd 100644 --- a/docs/project-memory/shared-memory/development-workflow.md +++ b/docs/project-memory/shared-memory/development-workflow.md @@ -120,6 +120,9 @@ AGC Rust 两条 lane、crates、smoke、Backend 和桌面壳测试使用镜像 `.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=` 只跑自己那片,片内保持 `--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 镜像缓存,再重跑门禁。 +根 `vitest.config.ts` 固定 `test.silent: true`(`--silent` 的配置形态,silent is gold):成功用例不回放被测代码写进 stdout / stderr 的内容(React `act(...)` 警告、`scripts/dev*.test.ts` 的 dev 调度日志等),CI 日志只保留每个文件一行进度、最终汇总与失败用例的断言摘要加源码位置。`vitest.frontend-ci.config.ts` 通过 `mergeConfig` 继承该设置,AGC 与 repository checks 直接使用的根配置同样生效——所以不要改成只对某一个配置生效,那会让另一条 CI 测试重新刷屏。本机排查需要完整 console 输出时用 `vitest run --silent=false` 覆盖,不要改回 `silent: false`。`scripts/project-ci-workflow.test.ts` 有守护用例钉住这条口径。 + + ## 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`。 diff --git a/scripts/project-ci-workflow.test.ts b/scripts/project-ci-workflow.test.ts index 015533b15..923c6a6ac 100644 --- a/scripts/project-ci-workflow.test.ts +++ b/scripts/project-ci-workflow.test.ts @@ -75,6 +75,12 @@ const jobsWithoutNpmInstall: readonly string[] = [ const rootPackageJson = JSON.parse( readFileSync(resolve(process.cwd(), 'package.json'), 'utf8'), ) as { scripts?: Record }; +// 前端与 AGC 的 CI 测试都跑根 vitest 配置(`vitest.frontend-ci.config.ts` 也 merge 它), +// 这里钉住「成功用例静默」,避免有人顺手删掉后 CI 日志重新被 act 警告与 dev 日志刷屏。 +const rootVitestConfig = readFileSync( + resolve(process.cwd(), 'vitest.config.ts'), + 'utf8', +); const nativeShellGateScript = readFileSync( resolve(process.cwd(), 'scripts/check-native-shells.mjs'), 'utf8', @@ -540,6 +546,10 @@ describe('project CI workflow', () => { ).toHaveLength(2); }); + it('keeps passing CI tests silent so only failures reach the log', () => { + expect(rootVitestConfig).toMatch(/^\s*silent:\s*true,$/mu); + }); + it('keeps frontend, operations fixture, and native shell gates in dedicated jobs', () => { const frontendJob = jobSection('frontend-tests'); expect(frontendJob).toMatch(/^ {8}run: npm run test:ci:frontend$/mu); diff --git a/vitest.config.ts b/vitest.config.ts index 2d66a04ff..6401f100f 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -94,6 +94,10 @@ export default defineConfig({ test: { environment: 'node', globals: true, + // 成功用例不回放被测代码写进 stdout / stderr 的内容:CI 日志里只保留每个 + // 失败用例的断言摘要,避免 React act 警告、dev 调度日志这类噪音刷屏。 + // 需要在本机排查时用 `vitest run --silent=false` 覆盖本次配置。 + silent: true, minThreads: 1, maxThreads: 8, server: {