Merge branch 'master' into fix/chat-status-lost
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
# Conflicts: # docs/project-memory/shared-memory/decision-log.md # docs/project-memory/shared-memory/pitfalls.md
This commit is contained in:
@@ -2,6 +2,41 @@
|
||||
|
||||
> 用途:记录已经确认、会影响后续开发的长期技术/产品/协作决策。短期讨论不要写在这里。
|
||||
> 当前口径:历史条目的旧路径、旧版本和已退役对象只用于追溯,不构成现行实现依据;如与当前代码或 `docs/README.md` 冲突,以当前代码和最新专题文档为准。
|
||||
## 2026-09-16 抠图模式与背景色契约
|
||||
|
||||
- External v1 抠图和 AGC `agc_remove_background` 支持 `complex`(语义分割识别前景)与 `flat`(纯色背景抠图);明确纯色背景优先 flat,模式缺省仍为 complex,主站前端保持现有行为。
|
||||
- flat 的颜色允许 `auto`、`#RRGGBB` 或省略,自动识别完全由 BgFilter 负责。主站只校验、透传,不调用视觉模型选色;complex 携带颜色、非法值和空字符串在入队前拒绝。
|
||||
- 来源、名称、模式与颜色共同区分客户端请求意图;旧参数调用及旧 External 请求的幂等指纹须保持稳定。
|
||||
- 权威合同:[AGC 抠图模式与背景色透传](../../technical/【技术方案】AGC抠图模式与背景色透传-2026-09-16.md)。
|
||||
|
||||
## 2026-09-16 策划 Agent 工具执行退出项目级写锁并自动接续中断批次
|
||||
|
||||
- 背景:策划 Agent 每个 `read_file` / `write_file` / `patch_file` 工具都在执行前竞争全局项目写锁,但同一会话已由 `.agent/design-agent/active.lock` 串行化,工具目标又限定在 `design_artifacts`;项目锁既不覆盖「工具 + 会话 checkpoint」事务,还把进程中断时的 `executing=true` 不确定窗口扩大到等锁与工具执行全程。真机项目出现 `pendingBatch.executing=true`、`function_call` 无配对 output、UI 只显示工作中且无错误的状态。
|
||||
- 决策:单次策划工具不再竞争项目级写锁,只保留策划命令锁与既有原子写入;GameAgent / DirectProject 的公共项目锁实现与调用不变。重开项目 hydrate 时,若命令锁可获取且当前批次处于 `executing=true`、当前 call 无 output,则自动续跑原回合:为该 call 补写「执行结果未保存」的工具错误、跳过剩余调用并交回 Provider 自愈;不得重放文件副作用,也不要求用户手动重试。
|
||||
- 验证:新增定向用例证明中断批次自动补齐工具 output、收到后续 assistant 回复、清空 pendingBatch 并结束原 turn,同时目标文件保持未修改(未重放 `patch_file`);策划 Runtime 定向 14 条、策划工具 3 条通过,`cargo fmt --check`、`npm run check:encoding`、`git diff --check` 通过。
|
||||
- 关联文档:[策划 Agent 生产迁移与工作区浏览](../../technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md)。
|
||||
|
||||
## 2026-09-16 AGC 同 AppData 多窗口共享 Agent Runner
|
||||
|
||||
- 背景:双击或再次启动 AGC 客户端时报「应用启动失败」,启动日志为 `startup.runner.owner-lock.failed details=AI 游戏创作界面已由同一 AppData 目录中的其他进程运行`。原设计(2026-07-27 / 2026-08-23)要求同一 AppData 只有一个 GUI owner,第二个界面进程在 setup 阶段就失败退出。
|
||||
- 决策(锁语义):`agent-runner.gui-owner.lock` 改为**界面参与锁** `agent-runner.gui-participant.lock`,以共享句柄打开,同一 AppData 的任意数量窗口可同时持有;Runner 的启动检查、attach 门禁与 watchdog 只用“能否独占取得该文件”判断是否仍有窗口存活。全部窗口退出后才关停 Runner 并清理 endpoint。
|
||||
- 决策(claim 采纳与发布):窗口启动先**采纳**durable claim(同一 epoch/revision),只有 claim 缺失或不可读才发布新 claim;登录、refresh、退出或换号才发布新 claim(新 epoch + 本窗口 revision),成为新的登录态权威。同一 claim 的重复 attach 是幂等空操作,不再清空 Runner 登录态;只有 epoch 变化或携带明确登出参数才允许替换 / 清空。并发发布以最后一次成功写入的 claim 为准,落败窗口按最新 claim 有界重试。
|
||||
- 决策(事件与退出):manifest 失效与 Runtime update relay 的接收端从单槽改为按 `event_sink_token` 去重的注册表并广播,发送失败只淘汰该接收端;GUI 退出先释放本窗口参与锁,仍有其它窗口时保留 Runner(`agent.runner.gui_exit.retained_for_other_windows`),最后一个窗口才请求关闭。Runner 启动失败时先按最新 endpoint 复用一次,避免两个窗口同时冷启动时的实例锁竞争被误报成启动失败。
|
||||
- 边界:本机 GUI ↔ Runner 协议方法与参数不变,不引入多 Runner、不做跨 AppData 会话共享;项目级 `.agent/project.lock` 不变,多窗口仍不能并行写同一项目;平台登录态 generation 单调与 claim 失配失败关闭语义保持不变;混用新旧版本二进制访问同一 AppData 不属于支持场景。
|
||||
- 验证:定向 Rust `runner::tests::gui_owner_*` 11 条与新增的参与锁多窗口 / 存活判定 / claim 采纳与轮换 / 同 claim 第二个窗口不清空登录态用例全部通过;真实 debug 二进制 Windows smoke 证明同一 AppData 两个 GUI 都完成 `startup.setup.complete`、只存在一个 `--agent-runner` 进程、关闭一个窗口后另一个窗口与 Runner 继续存活、最后一个窗口退出后 Runner 退出并删除 endpoint;`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` 通过。
|
||||
- 未验证 / 已知环境问题:真实安装包双开需要重新构建发布后才能验证;`durable_provider_handoff_prevents_shutdown_even_when_corrupt`、`durable_provider_retry_prevents_shutdown_and_reopens_writes`、`runtime_interrupt_for_true_steer_decision_only_interrupts_older_provider_cursor` 三条用例在本机改动前的基线上即失败(Windows 安全对象 owner 校验与 Provider 请求重复),与本决策无关。
|
||||
- 关联文档:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`(2026-09-16 节)、`docs/project-memory/plans/【里程碑】AGC同AppData多窗口共享Runner-2026-09-16.md`。
|
||||
|
||||
## 2026-09-16 DirectProject 三维请求解除 Phaser 固定约束,由 Codex 自选技术栈
|
||||
|
||||
- 背景:三维需求("做个 3D 城市游戏")在只有 Phaser 4 二维通道的工程里没有落点,而完成判定以"源码引用已登记平台图片 + 浏览器渲染到该图"为硬门禁,模型可推进的唯一动作退化成生成图集;真机侧表现为长时间生图与反复接线,等轴伪 3D 成了默认交付。产品决定不再用"先澄清引擎"卡住三维请求,改为放开选型。
|
||||
- 决策:用户消息表达三维(3D / 三维)且没有点名引擎时,本回合注入**自选技术栈合同**:不受"新 Web 游戏固定 Phaser 4.2.1"约束,由 Codex 自行选择三维技术栈(Three.js、Babylon.js 等 npm 运行时,或当前工程自带的引擎),可以按需新增 npm 依赖、调整工程结构,并在回复里说明选型;客户端不要求先澄清、不阻断任何工具、不拒绝登记产出。
|
||||
- 决策(常驻口径):`DIRECT_AGC_ENGINEERING_GUIDANCE` 的 Phaser 固定约束按二维/三维分层——二维游戏仍是 Phaser 4.2.1,三维请求不受该约束。首页回合只加一行三维提示,仍允许按既有规则创建项目。
|
||||
- 边界:用户点名引擎时沿用既有工程合同(Cocos / Unity / Godot 等与当前目录不匹配时先说明不匹配);用户主动选择"等轴 / 伪 3D / 2.5D"或话题是代码里的三维概念时不注入合同。唯一保留的红线是不得用等轴伪 3D 或二维图集冒充三维交付而不说明。识别只读用户原文,不改写消息、不触发额外工作流,也不做工具阻断或注册门禁。
|
||||
- 影响范围:`apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/mod.rs`。**未改** `/api/external/v1` 契约 / OpenAPI / DTO、SpacetimeDB schema、AGC 工具桥行为、前端投影与资源工作台。
|
||||
- 验证方式:`three_dimensional_game_request_frees_the_engine_choice`、`explicit_flat_presentation_requests_do_not_trigger_three_dimensional_selection`、`named_engine_requests_keep_the_existing_engineering_rule`、`three_dimensional_contract_reports_the_current_project_engine`、`home_three_dimensional_note_keeps_project_creation_available`、`system_prompt_is_bounded_and_declares_direct_runtime`,以及 `agent::direct_tools_mcp` 17 passed;`cargo fmt --check` 通过。本机临时目录 owner ACL 与进程用户不一致,涉及 `init_local_game_project_at` 的既有用例(含未改动模块)在本机无法执行,全量分片与真机 smoke 未在本轮取得。
|
||||
- 关联文档:[里程碑](../plans/【里程碑】Direct三维请求自选技术栈-2026-09-16.md)、[实施计划](../plans/【实施计划】Direct三维请求自选技术栈-2026-09-16.md)。
|
||||
|
||||
## 2026-09-17 DirectProject 历史分页的「可显示」口径定为前端回合反馈,一次翻页连拉上限 5 页
|
||||
|
||||
- 背景:ADR 与里程碑要求「一次翻页操作在前端自动连拉,直到出现可显示条目或 `hasMore=false`,上限 5 页」,但实现只落地了后端锚点与文件尾回扫,前端仍是单发一页。历史切片的 `limit` 按原始条目计,一整页全是工具卡片 / 思考文本且落进同一个已渲染回合的折叠「执行过程」时,用户点「显示更早的对话」看不到任何变化。
|
||||
@@ -8776,7 +8811,22 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 决策:新增 `agent/runtime_error.rs` 作为统一错误事件与有界诊断 sidecar 边界。DirectProject 失败、Agent Runtime terminal failure 均持久化 `.agent/runtime/errors/<eventId>.json`,并将脱敏 assistant 终态写回 `project.jsonl`;前端只通过 `read_agent_runtime_error_detail` 读取脱敏详情。旧 `failure.json` 保留兼容,不把原始 stderr、凭据、URL/query、宿主绝对路径写入用户文本。
|
||||
- 决策:错误使用稳定 `source / stage / code / retryable / publicText / recoveryHint / detailRef` 字段;试玩 attempt 越界返回终态错误并停止继续等待。素材完成门扫描实际 npm 源码模块,并把 manifest 中合法的自定义 art-spritesheet 路径纳入候选,构建和浏览器观察仍需通过既有完成门。
|
||||
- 关联规范:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的“2026-09-15 AGC 统一错误事件、诊断落库与验收反馈”;开发期计划见 `docs/project-memory/plans/【里程碑】AGC统一错误诊断与验收反馈-2026-09-15.md` 与对应实施计划。
|
||||
|
||||
## 2026-09-16 平台会话身份与凭据分离
|
||||
|
||||
- 背景:长回合保活和 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` 与对应实施计划。
|
||||
- 验证: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 回合跨页面继续运行与活动项目面板
|
||||
|
||||
- 决策:采用后台继续运行语义。Direct 回合由进程内项目身份锁持有,页面离开不取消;重进项目通过活动回合只读快照与 Thread Manager bootstrap/consume 恢复忙碌态和进度。左上角面板复用同一快照列出正在运行的 Direct 项目并支持进入。
|
||||
- 边界:快照不写项目文件、不进入公共 API、不跨应用重启恢复;读取失败保留上一份结果并单独提示,不改写成权限或审批失败。身份锁排他性、付费身份和项目写锁不变。
|
||||
|
||||
## 2026-09-16 CI 宿主 CPU 上限:Jenkins 16 核 / Gitea Actions runner 12 核
|
||||
|
||||
- 背景:`genarrative-station`(32 逻辑核)上 Jenkins Built-In Node 与 Gitea Actions runner 共用同一宿主。Jenkins `jenkins.service` 原先没有任何 CPU 限制(`cpu.max=max`),构建期 Web / Api / Stdb 三分支并行(Vitest 8 线程 + 两次默认 32 job 的 cargo)把整机顶到 80%~95%;`gitea-runner` 容器 `--cpus=24`(75%)在 push 触发的 CI 波峰里实测峰值 24.8~25.3 核,是同一时间窗里更大的单一消耗方。
|
||||
- 决策:两路 CI 都设硬上限。Jenkins 侧 `systemctl set-property jenkins.service CPUQuota=1600%`(16 核 / 50%,覆盖 Built-In Node 上所有子构建,立即生效、无需重启,drop-in 落 `/etc/systemd/system.control/jenkins.service.d/50-CPUQuota.conf`)。runner 侧把 `/opt/gitea-stack/compose.yml` 的 `cpus` 由 `"24.0"` 改为 `"12.0"`(12 核 / 37.5%),并用 `docker update --cpus=12 gitea-runner` 让运行中的容器立即生效,不重建容器、不中断在跑 job。
|
||||
- 边界:Deploy 阶段在远端 dev / release agent 执行,不受该上限约束。调整只动这两处:`systemctl set-property / revert jenkins.service`、`docker update --cpus=<n> gitea-runner` 加同步 compose(备份 `/opt/gitea-stack/compose.yml.bak-<时间戳>`)。
|
||||
- 验证:限速后 `Genarrative-Full-Build-And-Deploy` #289 / #290 SUCCESS;采样期 Jenkins 峰值 10.2~10.5 核、限流不足 2s(可忽略),runner 峰值 12.07 核且持续出现 throttling,整机回落到 2.6%~19.8%。
|
||||
- 关联文档:[开发运维](../../【开发运维】本地开发验证与生产运维-2026-05-15.md)。
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
## 标准流程
|
||||
|
||||
前端测试稳定性验证使用根目录 `npm test`(与 Frontend tests job 相同),保留 Vitest 的 8 worker 上限。涉及异步资源展示时,组件测试必须 mock 所有会触发的网络请求,每次调用创建独立 `Response`,并等待最终 DOM 状态而非仅等待 fetch 被调用。换签 Hook 的测试通过 `vitest.config.ts` 的 include 纳入全量运行;新增测试文件后需确认实际执行名单,命令参数指定文件不会绕过 include 白名单。排查顺序依赖可使用 `npm test -- --sequence.shuffle --sequence.seed=9467`,但不能以重试成功替代失败原因分析。
|
||||
|
||||
用例隔离必须包括浏览器状态与 mock 实现:修改 `window.history` 后恢复基线路由;`spyOn(window, 'getSelection')` 等 spy 在用例结束后 restore;`clearAllMocks` 仅清调用记录,不能恢复被上一个用例替换的返回值。顺序打乱暴露的失败应修复泄漏来源,保留原有业务断言。
|
||||
|
||||
```text
|
||||
确认工作树与目标分支 → 读取入口和当前专题 → 查代码真相 → 小步修改 → 定向验证 → 更新当前文档/记忆 → 检查提交边界
|
||||
```
|
||||
@@ -72,6 +76,10 @@ SpacetimeDB 任务统一先读取 `.codex/skills/genarrative-spacetimedb/SKILL.m
|
||||
3. 确认相关当前文档与共享记忆已同步,且 docs 入口没有指向已删除或退役实现依据。
|
||||
4. 提交标题使用中文,标题后逐行写明本次变更。
|
||||
|
||||
## Jenkins 定时版本调度
|
||||
|
||||
定时与版本比较只保留在 `Genarrative-Scheduled-Revision-Trigger` 一处:每小时用 `git ls-remote` 解析 `SOURCE_BRANCH` 远端 HEAD,与上一次触发过的 revision 比较,变化时才把同一个 `COMMIT_HASH` 同时传给 `Genarrative-Full-Build-And-Deploy` 与 `Genarrative-Agc-Windows-Build`,保证两条管线构建同一个版本。`Genarrative-Full-Build-And-Deploy` 与 `Genarrative-Agc-Windows-Build` 不得自带 `triggers` / `cron`,也不得在管线内再做一套版本去重;`npm run check:production-ops` 会拦住这两类回退。调度状态与生效步骤见 `docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
|
||||
## Gitea CI 依赖闭合
|
||||
|
||||
`.gitea/workflows/project-ci.yml` 的客户端门禁拆成八个 job,每个 job 只预热自己会构建的那几份依赖:`AI game creator shell Rust shard 1/4` 到 `4/4` 各只预取 AGC 壳 manifest 并各跑一片(AGC 壳那份 `Cargo.lock` 的 path 依赖已含 `platform-llm`、`platform-agent`、`agent-runtime-core` 与 `shared-contracts`),`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,不预热。AGC 壳的 4 个分片 job、smoke job 与 crates job 只用 cargo 与 node 内建模块,因此不执行 `npm ci`。两个被 `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 片:CI 的每个分片 job 用 `--shard-index=<i>` 只跑自己那片,片内保持 `--test-threads=1` 并各自使用独立 `TMPDIR`,片与片之间靠 job 级并发摊开;本地不传 `--shard-index` 时仍是同一条命令把 4 片放进程里并行。不要改回「一个 job 内多进程并行这几片」——同一容器里它们会争抢共享 `HOME`、target 目录与固定临时路径,实测比整套串行还慢。每个分片 job 都会自校验「片并集等于全集且互斥」,因此改分片规则不会静默漏跑。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 镜像缓存,再重跑门禁。
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# 踩坑与排障记录
|
||||
|
||||
## JSON 卡片显示与 UI 编辑能力必须同源
|
||||
|
||||
JSON 的文本读取分支不等于卡面应该展示原始 State 摘要。卡片、缩略图及编辑器入口共同消费受控文本预览的 `uiDesignAssetId`;只有原生复用 UI 持久化合同校验 schema、完整 State 和项目/资产身份后才设置它。普通 JSON 保留 JSON 代码预览,不按 `kind: UI/ui` 或 schema 字符串片段猜测编辑能力。已有合法 UI State 的加载/保存不依赖 kind 精确大小写,但新建初始化仍保留正式 UI 资产门禁;缓存与项目切换须保留现有身份隔离。
|
||||
|
||||
## 窗口 Context 发布不得依赖每次渲染新建的业务回调
|
||||
|
||||
工作台向窗口标题栏发布运行项目时,若 effect 依赖普通函数派生的回调,发布 Context 会重新渲染工作台,进而再次发布并清理,形成更新深度循环。转发入口须稳定,并在提交阶段更新实际处理器引用;发布数据变化与卸载清理分开。回归测试必须组合真实窗口 Provider 和工作台消费者,只有独立画布测试无法覆盖这条反馈链;回归时用有界发布次数阻止测试失控。画布快速操作时暴露的更新深度错误,也须检查外层状态同步,不能直接归因于滚轮频率。
|
||||
|
||||
## 2026-09-16 从 Codex 里启动 AGC 客户端会看到被重定向的 `%APPDATA%`
|
||||
|
||||
- **现象**:在 Codex 会话里用 `Start-Process` 启动 `genarrative-ai-game-creator-shell.exe` 做排障时,子进程写 `C:\Users\<user>\AppData\Roaming\world.genarrative.ai-game-creator\...` 的内容会落到 `C:\Users\<user>\AppData\Local\Packages\OpenAI.Codex_2p2nqsd0c76g0\LocalCache\Roaming\...`;同一个 `Test-Path` / `Get-ChildItem` 命中的是重定向视图,只有 `\\?\C:\Users\...` 形式能区分真实路径。
|
||||
- **影响**:用 agent 拉起的客户端复现「多开 / 登录态冲突 / 锁文件被占用」类问题时,可能与用户双击开始菜单快捷方式的真实进程不是同一份 AppData,从而得出「两个实例没有互相冲突」或「日志里没有那条失败」的错误结论。
|
||||
- **处理**:把用户双击快捷方式(或从 Codex 之外启动)的进程作为唯一用户侧证据;核对待查文件时同时比对真实 `AppData\Roaming` 路径与 `Packages\...\LocalCache\Roaming` 路径;排障结论里写明客户端是「谁启动的」。
|
||||
|
||||
## Windows 已登记生图资产未刷新
|
||||
|
||||
Direct 工具桥会 canonicalize 项目根,事件中的路径可能带 `\\?\` / `\\?\UNC\`,而前端项目路径仍是普通盘符或 UNC。失效监听不能直接比较原始字符串;识别为同一项目后,用当前项目路径重读 manifest,保留项目切换与 revision 门禁。普通 `agc_generate_image` 成功提交也必须发出失效通知,不能依赖整轮 Agent 结束。回归需覆盖两种 Windows 前缀、其它项目事件拒收,以及 Agent 尚未结束和后续失败时已登记图片卡片仍可见。
|
||||
@@ -3875,7 +3889,7 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
- 现象:在 Jenkins Job 页面给 `MIGRATION_BOOTSTRAP_SECRET_CREDENTIAL_ID` 配了默认值,下一次加载 Declarative Pipeline 后又变空或恢复旧描述;04:00 Full Job 还可能因默认选择 `pause-after-stdb` 且 approvers 为空而失败。
|
||||
- 原因:这些 Job 使用 Pipeline script from SCM,`parameters {}` 和 `triggers {}` 会作为 Job property 回写现场配置;只改 UI 不是持久修复。构建编排如果不显式关闭下游 `PUBLISH_AFTER_BUILD`,还会受下游默认值漂移影响。
|
||||
- 处理:credential ID 和参数默认值写回三个 Jenkinsfile;仅供开发使用的 dev 定时 Full Job 默认 `STDB_API_ROLLOUT_MODE=normal`,三路 Build 调用显式传 `PUBLISH_AFTER_BUILD=false`,再由 Full Job 统一按 Stdb → API → Web 发布。Secret 原文只放 Jenkins Secret File,旧 Secret Text 保留给 Import / Export。
|
||||
- 验证:推送后让 Full / Stdb Build 用不存在的源码分支在 checkout 阶段 fail-closed,让 Stdb Publish 用空构建版本在 Prepare 阶段 fail-closed,以安全刷新参数 schema;随后只读检查三个 live `config.xml` 的参数描述和默认值,确认 Full timer 仍为 `0 4 * * *`、rollout 默认值为 `normal`,并确认刷新运行未进入 publish / deploy stage。
|
||||
- 验证:推送后让 Full / Stdb Build 用不存在的源码分支在 checkout 阶段 fail-closed,让 Stdb Publish 用空构建版本在 Prepare 阶段 fail-closed,以安全刷新参数 schema;随后只读检查三个 live `config.xml` 的参数描述和默认值,确认 rollout 默认值为 `normal`、Full 与 AGC Job 都不再带 cron(定时只来自 `Genarrative-Scheduled-Revision-Trigger`),并确认刷新运行未进入 publish / deploy stage。
|
||||
- 关联:`jenkins/Jenkinsfile.production-full-build-and-deploy`、`jenkins/Jenkinsfile.production-stdb-module-build`、`jenkins/Jenkinsfile.production-stdb-module-publish`、`scripts/check-production-ops-guardrails.mjs`。
|
||||
|
||||
## 维护模式内网全站放行不能信任 X-Forwarded-For
|
||||
@@ -5614,9 +5628,36 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
|
||||
- 在 hook 内运行临时仓库测试时,`cwd` 不会覆盖继承的 `GIT_DIR`、`GIT_WORK_TREE` 或 `GIT_INDEX_FILE`。未隔离的 Git/lint-staged 子进程可能向真实仓库提交 fixture,甚至把测试版 ESLint、Prettier 配置带入主分支。
|
||||
- fixture 子进程统一清除 `GIT_*` 环境,并用一次性外层 linked worktree 验证引用、索引、配置不变;原有工程检查规则保持完整,不能用逐项关闭规则修复 fixture 污染。
|
||||
- 2026-09-16 复核:从链接工作树 `git push`/`git commit` 时,Git 注入 `GIT_DIR=<主仓库>/.git/worktrees/<name>`、`GIT_WORK_TREE`、`GIT_INDEX_FILE`,husky → npm → `check:repository-ci` → 夹具测试整链条继承。夹具 `git config user.name "Git Hooks Test"` 会写进共享 `.git/config`(此后所有提交 author 变成 `Git Hooks Test`);夹具 `git init` 按是否带 `GIT_WORK_TREE` 分别写成 `core.bare=true`(`fatal: this operation must be run in a work tree`)或 `core.worktree=<临时夹具目录>`(`git status` 实际在操作临时目录)。
|
||||
- 处理:钩子与门禁入口先 `unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_COMMON_DIR GIT_PREFIX GIT_CONFIG_PARAMETERS GIT_CEILING_DIRECTORIES`;夹具 Git 调用在命令前自检 `rev-parse --show-toplevel` 等于夹具目录,落到外部仓库立即失败;守卫用例的子进程必须真的继承 `GIT_DIR`,否则断言会空转。
|
||||
- 验证:`git config --show-origin --get user.name` 出现 `file:.git/config Git Hooks Test`、`git rev-parse --show-toplevel` 指向 `%TEMP%\genarrative-pre-push-*\repo` 都是被污染的确定性证据;被 `core.worktree` 劫持期间执行的 `git pull` 会把检出写进临时目录,真实工作树整体落后(本次 93 个文件),配置修好后用 `git checkout HEAD -- .` 回填。
|
||||
- Vitest 的 `toHaveBeenCalledWith` 匹配任意一次调用,失败输出会列出其它命令;应先定位相同命令的真实参数差异,不能由其它调用的序号推断时序故障。
|
||||
- 存在后台轮询的 IPC mock 不应要求目标命令占据全局最后一次调用。验证刷新时先记录调用边界,再筛选该边界之后的目标命令,严格核对其最后一次参数,避免后台查询影响断言,也避免旧调用掩盖刷新未执行。
|
||||
|
||||
## 2026-09-16 并发生图遇到“登录态冲突”:身份代次与凭据轮换混用
|
||||
|
||||
- **现象**:DirectProject 长回合里并发派发的生图 / 素材生成请求中途报 `authentication-required: 陶泥儿登录态已变化,旧账号请求已停止,请使用当前账号重试`,或平台工具返回 `HTTP 401 invalid-token`;账号并没有切换,重新登录后短时间内可复现。
|
||||
- **原因**:客户端把两件事压成了一个判据。原生冻结会话(`PlatformSessionSnapshot`)同时承担“身份归属”和“access token 字节比对”,而长回合保活与 401 续期每次都会签发新 token 并推进 native generation 重新安装会话;于是同账号的正常续期被等价成换号,续期窗口内所有在途生成、编辑、上传、确认和下载 operation 全部失配。保活定时器(回合 busy 时每 5 分钟一次)会稳定落在生图窗口内,所以并发越多越必现。另一层在服务端:`/api/auth/refresh` 是严格一次性轮换,且失败时下发清空 refresh cookie 的响应;两个窗口 / 实例并发续期时,输的一方会把赢家刚写入的有效 cookie 删掉。
|
||||
- **处理(现行口径)**:平台会话统一拆成**身份**(`userId + api origin + identity generation`)与**凭据**(当前 access token)。identity generation 只在登录、切号、登出和新的 GUI authority epoch 推进;同账号续期只更新凭据并推进写入 revision(revision 只用于拒绝迟到写入)。冻结会话校验只比身份,比 token 字节的判据已被取代。刷新失败语义收紧为:只有服务端明确返回 401/403 且经一次收敛重试后仍失败,才清本地会话;网络错误、5xx、网关错误和响应契约异常必须保留会话与 access token。`/api/auth/refresh` 的轮换失败不再下发清 cookie 响应。
|
||||
- **验证**:AGC `platform_session::tests` 覆盖“同身份 token 轮换后冻结会话仍有效”“换号 / 退出后失效”“迟到 install 被 revision 拒绝”;`appSurface` 前端用例覆盖“续期不推进身份代次且 native 写入 revision 递增”“瞬时刷新失败不清会话”;网站 `src/services/apiClient.test.ts` 覆盖“刷新 401 后收敛重试成功”与“两次都被拒绝才判权威失效”;`api-server` `refresh_session_*` 覆盖“轮换失败不下发清 cookie”。定位同类问题先看冻结会话判据里有没有 token 字节,再看服务端失败响应有没有 `Max-Age=0`。
|
||||
|
||||
## 2026-09-16 同步 Tauri 命令里 `tokio::spawn`:点「终止」整个客户端 abort 闪退
|
||||
|
||||
- **现象**:AGC 客户端(陶泥儿 0.1.46 安装包,`C:\Users\<用户>\AppData\Local\陶泥儿\genarrative-ai-game-creator-shell.exe`)在对话回合运行中点输入盒的「终止」后整个 App 直接消失。Windows 事件日志 `Application Error` 1000:异常代码 `0xc0000409`、出错模块就是该 exe、偏移 `0x3395066`;`%LOCALAPPDATA%\CrashDumps` 留下同名 minidump,其 ExceptionStream 为 `NumberParameters=1`、`Param[0]=7`(`FAST_FAIL_FATAL_APP_EXIT`)⇒ Rust `abort()`,既不是栈溢出(`0xC00000FD`)也不是访问违例(`0xC0000005`)。
|
||||
- **原因**:`cancel_direct_codex_turn` 是**同步** Tauri 命令,Tauri 把非 `async` 命令直接跑在 IPC 回调线程(Windows 上是 WebView2 的 UI 线程);该线程没有进入任何 tokio runtime 上下文(`main` 只 `tauri::async_runtime::set(handle)` 加泄漏 Runtime,从未在调用线程 `enter()`)。终止链路 `cancel_direct_codex_turn_at → CodexTurnStartCancellation::cancel → maybe_interrupt` 却用 `tokio::spawn` 派发 `turn/interrupt`:在没有上下文的线程上 `tokio::spawn` 经 `Handle::current()` panic("there is no reactor running"),panic 又跨不过 Tauri 的 IPC 回调边界,Rust 只能 abort 整个进程。同一模块的 `CodexThreadLease::drop`、`CodexTurnGuard::drop` 是同一形态。引入点是 2026-09-15 23:37 的 `76bbeb684 重构 DirectProject Agent 深模块`;既有覆盖只有 `#[cfg(unix)]` 的 `#[tokio::test]` 走 Drop 守卫路径,碰不到同步命令线程,所以 CI 全绿。
|
||||
- **处理**:`codex_app_server/mod.rs` 新增 `spawn_codex_app_server_task`,统一经 `tauri::async_runtime::spawn` 派发(生产环境就是 `main` 装的深栈 runtime);终止、租约 Drop、回合 Drop 三处一起改走它。判据是「调用点可能位于没有 tokio 上下文的线程」,不是「这个函数看起来像异步」。
|
||||
- **验证**:新增 `codex_app_server_task_dispatch_needs_no_tokio_runtime_context`——在 `std::thread::spawn` 出来的无上下文线程里调用派发入口,若回退成 `tokio::spawn` 即失败(实测回退后报 `there is no reactor running, must be called from the context of a Tokio 1.x runtime`)。
|
||||
- **排障注意**: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-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 上。
|
||||
- **原因**:crate 里的 ts-rs 导出会按**本机依赖版本**重写 `src/features/project-workspace/generated/DirectCodexUser*.ts`:注释头变成 "This file was generated…"、字符串改双引号、`DirectCodexUserMessageItem` 丢掉 `type: 'message'` 判别字段、并多出一个 `DirectCodexUserMessageEnvelope.ts`。仓库里提交的那份是前端真正依赖的形状(前端按带 `type` 的判别联合写),重写后两边就对不上——错在生成器版本漂移,不在前端。
|
||||
- **处理(现行口径)**:不要把重写结果当改动提交。跑过 `cargo test` 或构建后先 `git checkout -- apps/ai-game-creator-shell/src/features/project-workspace/generated`,再删掉多出来的 `DirectCodexUserMessageEnvelope.ts`,然后才做 typecheck / 打包;绑定与前端形状冲突时以**已提交的绑定 + 前端**为基准排查。
|
||||
- **验证**:恢复提交版本后 `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-16 Node 26 下 vitest 的 jsdom 用例拿不到 window.localStorage
|
||||
|
||||
- **现象**:只声明 `@vitest-environment jsdom` 的用例里 `window.localStorage` 是 `undefined`(典型报错 `Cannot read properties of undefined (reading 'clear')`);而 `appSurface.test.ts` 里同样访问 `window.localStorage` 却一切正常。
|
||||
|
||||
@@ -51,6 +51,8 @@ SpacetimeDB crate、SDK、CLI / standalone 与生成 bindings 按 `2.8.3` 对齐
|
||||
|
||||
## AGC DirectProject 与 UI workflow
|
||||
|
||||
- AGC 的本地 `llm.customEnabled` 默认关闭,只能手动修改配置文件;开启后设置支持自定义 Responses 端点、读取 `/models`、勾选和预览 `visibleModels`。对话下拉只显示勾选项,LLM 请求经客户端凭据代理直连自定义上游;不会回退官方中转,平台资源服务仍使用账号权限。详见 AGC 后台模型别名与对话选择规范。
|
||||
|
||||
- DirectProject 对话先在完整历史中按回合/原始 item 身份关联,再分页渲染;每个回合只有一个呈现入口。有流按 item `seq` 交替文本和工具,无流采用历史正文;禁止位置猜配或同时展示累计回复与 item 正文。流写入单调归并,收尾等待落盘任务,不按磁盘“最后一段”猜最终回复位置。详见 AGC 实施计划的“DirectProject 回合展示唯一归属”。
|
||||
- 回合生命周期只由活动 client 回合快照和 Direct 事件恢复;Provider 的历史终态通知不能创建活动 client 回合。消息发送时间保存在历史信封,原始 item 不混入宿主字段;完成后的中间文本和工具默认收进“执行过程”,最终回复及失败提示保持可见。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user