Files
Genarrative/.hermes/shared-memory/pitfalls.md
2026-05-08 11:44:42 +08:00

17 KiB
Raw Blame History

踩坑与排障记录

用途:记录已验证、未来很可能再次遇到的问题。每条都应包含现象、原因、处理方式和验证方式。

记录格式

## 问题标题

- 现象:看到什么错误或异常行为
- 原因:确认后的根因
- 处理:具体修复步骤
- 验证:如何确认修复有效
- 关联:相关文件、文档、提交或 Issue

中文乱码与编码风险

  • 现象:中文文案、注释、剧情或文档显示为乱码,或被改写成英文。
  • 原因Windows/PowerShell/终端编码不一致,或整文件重写导致编码变化。
  • 处理:
    • 不要直接沿用乱码文本。
    • 不要用英文替换中文,除非用户明确要求翻译。
    • 在 PowerShell 5.1 中显式使用 UTF-8。
    • 优先用 Python/Node 或 Get-Content -Encoding UTF8 核对原文。
    • 修改中文文件时优先局部补丁,避免无关内容重写。
  • 验证:运行仓库已有编码检查;人工抽查修改文件中的中文内容。
  • 关联:AGENTS.mdnpm run check:encoding

.hermes 只放共享内容,不放个人 Hermes 配置

  • 现象:团队成员误把个人 Hermes 配置、会话或密钥复制进仓库。
  • 原因:仓库 .hermes/ 与个人 ~/.hermes/ 名称相似。
  • 处理:仓库 .hermes/ 只放 Markdown 共享记忆、计划和可公开 skills不提交 .envconfig.yamlsessions/auth.json
  • 验证:提交前检查 git diff -- .hermes,确认没有密钥、会话记录或个人路径敏感信息。
  • 关联:.hermes/README.md

旧后端路线文档造成判断漂移

  • 现象:开发时参考到 Express、Node、PostgreSQL 或 Go 方向旧文档,导致接口、数据真相或部署路径与当前主线不一致。
  • 原因:项目历史文档较多,部分旧方案仍保留作迁移参考。
  • 处理涉及服务端、数据真相、SpacetimeDB、运行时状态时先看 CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md,再看 DDD 总纲和具体技术方案。
  • 验证:代码改动应落在 server-rs + Axum + SpacetimeDB 主线;旧路线只作为迁移参考,不作为兼容目标。
  • 关联:docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.mdAGENTS.md

SpacetimeDB 表结构变更不能按 PostgreSQL 迁移直觉处理

  • 现象:发布时 schema 冲突、自动迁移拒绝、旧客户端调用 reducer 失败、private 表数据迁移遗漏。
  • 原因SpacetimeDB 对字段删除、类型变化、索引/主键/RLS/reducer 变化有不同自动迁移边界。
  • 处理:变更前阅读 SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md;涉及表变化时同步 migration.rsSPACETIMEDB_TABLE_CATALOG.md 和 bindings必要时走 JSON 导入导出与分片导入迁移流程。
  • 验证:发布前完成 schema 检查、bindings 生成、表目录更新和相关 smoke。
  • 关联:docs/technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.mddocs/technical/SPACETIMEDB_TABLE_CATALOG.md

本地 SpacetimeDB replica identity 不匹配

  • 现象:本地 standalone 启动时报 mismatched database identity
  • 原因root-dir / replica 数据残留与当前数据库身份不一致。
  • 处理:按本地 replica identity mismatch 文档进行备份、重建和脚本诊断。
  • 验证:本地 SpacetimeDB 可正常启动并 publish / 访问。
  • 关联:docs/technical/SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md

Vite SPA fallback 吞掉 API 请求

  • 现象:本地请求 /api/profile/* 等接口时返回 HTML被前端当 JSON 解析报错。
  • 原因Vite 代理缺少对应 /api/* 前缀API 请求落到 SPA fallback。
  • 处理:补齐 Vite 代理,让 API 请求转发到 Rust api-server
  • 验证:请求返回 JSON相关页面不再出现 HTML parse 错误。
  • 关联:docs/technical/PROFILE_MAIN_ROUTE_VITE_PROXY_FIX_2026-05-02.md

拼图 APIMart 图片生成密钥不能复用 DashScope / ARK key

  • 现象:拼图新手引导或拼图创作点击生成后返回 APIMart 图片生成密钥未配置
  • 原因:拼图 gpt-image-2 / nanobanana2 图片生成已按技术方案统一走 APIMart后端只读取 APIMART_BASE_URLAPIMART_API_KEYAPIMART_IMAGE_REQUEST_TIMEOUT_MS,不会用 DASHSCOPE_API_KEYLLM_API_KEYARK_API_KEY 兜底。
  • 处理:在本机私密配置 .env.secrets.local 或进程环境中配置真实 APIMART_API_KEY,不要提交到 Git填入后必须重启 api-server / npm run dev,运行中的进程不会自动加载新 env。
  • 验证:不打印密钥内容,只检查 APIMART_API_KEY 非空;重启后触发拼图生成不再返回本地配置缺失的 503。
  • 关联:docs/technical/PUZZLE_APIMART_IMAGE_MODEL_ROUTING_2026-05-01.md.codex/skills/gpt-image-2-apimart/SKILL.md

本地短信登录页签突然消失

  • 现象:登录弹窗只剩密码登录,短信登录页签看起来像被删掉,但 LoginScreen 中手机号验证码表单仍存在。
  • 原因:前端根据 GET /api/auth/login-options 返回的 availableLoginMethods 渲染页签;常见根因有两类:
    • 本地启动脚本没有让 .env.local 覆盖 .envSMS_AUTH_ENABLED=true 不生效,后端只返回 ["password"]
    • Rust API 直连已返回 ["phone","password"],但 Vite 代理目标指向未监听端口,导致 3000 域名下的 login-options 返回 500AuthGate 降级成 ["password"]
  • 处理:优先用 npm run api-servernpm run dev:rustnpm run dev 启动,这些入口应保持 shell 环境变量最高优先级,并允许 .env.local 覆盖 .env;完整栈启动时还要确保脚本计算出的 RUST_SERVER_TARGET 不被 .env.local 里的旧值覆盖。排查时先请求 3000 域名下的 /api/auth/login-options,再直连 Rust API 目标,并核对 .env.localSMS_AUTH_ENABLED 与代理端口。
  • 验证:http://127.0.0.1:3000/api/auth/login-options 返回至少 {"availableLoginMethods":["phone","password"]} 后,登录弹窗会恢复短信登录页签和“获取验证码”按钮。
  • 关联:scripts/api-server-dev.mjsscripts/api-server-maincloud.mjsscripts/dev-rust-stack.shscripts/dev-web-rust.mjsdocs/technical/AUTH_LOGIN_OPTIONS_DESIGN_2026-04-21.md

Rust 冷编译导致 api-server 健康检查误超时

  • 现象:npm run dev:rust 在 Windows 冷编译/链接阶段误判 /healthz 等待超时并杀掉 cargo run
  • 原因:脚本把 SpacetimeDB 与 api-server 等待窗口混在一起,未考虑 Rust 冷编译耗时。
  • 处理:按冷编译超时修复文档拆分等待窗口。
  • 验证:冷启动时不再误杀仍在编译的 api-server。
  • 关联:docs/technical/API_SERVER_DEV_STACK_COLD_BUILD_TIMEOUT_FIX_2026-04-25.md

Windows debug api-server 主线程栈溢出

  • 现象:cargo check -p api-serverbuild_router 测试通过,但 npm run api-server 在 Windows debug 启动时 thread 'main' has overflowed its stack
  • 原因:api-server Axum 路由树已经很深debug 主线程默认栈偏小,初始化状态和构造路由时容易触顶。
  • 处理:入口 main 用显式 16MB 栈线程启动 Tokio runtime并把实际服务逻辑放入 run_server();新增路由时优先用小 router .merge(),避免继续拉长主链。
  • 验证:npm run api-server/healthz 返回 200相关路由冒烟通过。
  • 关联:server-rs/crates/api-server/src/main.rsserver-rs/crates/api-server/src/app.rs

Windows debug 长 SSE Future 触发 api-server 断连

  • 现象:前端 Vite 代理请求 /api/runtime/creative-agent/sessions/{sessionId}/messages/streamread ECONNRESET,随后 api-server.exe0xffffffff 退出,dev:rust 回收 SpacetimeDB、Vite 和后台 Vite。
  • 原因:单个 async_stream::stream! 中塞入 Agent 执行、外部模型请求、会话更新和大量 SSE 事件,会在 Windows debug 下生成很大的 Future真实消费 SSE body 时容易触发 worker 线程栈压力或进程级中断,单元测试若只测函数和路由状态会漏掉。
  • 处理:长 SSE 路由优先使用 tokio::spawn 跑业务流程,通过 mpsc + UnboundedReceiverStream 向 Axum 返回轻量 stream失败时更新会话为 failed 并发送 SSE error,不要把大段执行逻辑内联到路由返回的 stream future 中。
  • 验证:补充实际 collect() SSE body 的路由测试,确认首轮包含 stagepuzzle_template_catalogdone,且不会提前发送 puzzle_template_selection / puzzle_cost_range;再执行 cargo check -p api-servercargo test -p api-server creative_agent,联调时用 npm run api-server 检查 /healthz
  • 关联:server-rs/crates/api-server/src/creative_agent.rsserver-rs/crates/api-server/src/app.rs

creative-agent 过程项不要把历史事件渲染成运行中

  • 现象:智能创作页过程中多个阶段从一开始同时转圈,生成结束或进入模板确认后仍有过程项保持转圈。
  • 原因:前端把历史 stagetool_startedthought_summary_delta 都按 active 渲染;后端工具开始/完成事件如果 toolCallId 不一致,也会导致开始事件无法收口。
  • 处理:
    • 只有最新且仍在执行的 stage 可为 active等待确认、等待用户、target ready 和 failed 都是静态状态。
    • 工具开始事件必须等同一 toolCallIdtool_completed 收口;兼容旧流时可按后续同名完成事件兜底。
    • 思考摘要只展示用户可见摘要,且流结束或会话进入等待/完成/失败态后必须改成 done。
  • 验证:前端测试断言完成后 CreativeAgentProcessItem 不再存在 tone === 'active';后端测试确认工具开始/完成事件使用相同 toolCallId
  • 关联:src/components/creative-agent/creativeAgentViewModel.tsserver-rs/crates/api-server/src/creative_agent.rsdocs/prd/CREATIVE_INTERACTIVE_AGENT_PHASE1_LANGCHAIN_RUST_PUZZLE_LOOP_PRD_2026-05-05.md

creative-agent 会话切换要清理本地待确认模板

  • 现象:用户在一个智能创作会话中点开模板确认面板后,立即切到另一条创作会话,可能看到上一会话的确认面板残留。
  • 原因:模板确认面板的 pendingSelectionCreativeAgentWorkspace 本地 UI 状态,不属于后端 session 快照;组件复用时如果不监听 sessionId 清理,会跨会话泄漏。
  • 处理:工作区以 session?.sessionId 为边界清空 pendingSelection;服务端仍以 puzzleTemplateSelection / targetBinding 作为正式业务状态。
  • 验证:前端测试先点开模板确认面板,再 rerender 到另一 session断言确认面板消失。
  • 关联:src/components/creative-agent/CreativeAgentWorkspace.tsxsrc/components/creative-agent/CreativeAgentWorkspace.test.tsx

视觉小说 VN-10 不要绕过平台资产引用

  • 现象:文档、封面、场景背景、角色立绘或音乐为了预览方便被写成 Data URL、裸对象路径、外部 URL 或本地临时文件路径。
  • 原因前端上传与预览容易混在一起若不走平台资产对象SpacetimeDB 和长期草稿会被大文本或大二进制污染。
  • 处理VN 资产统一用 /api/assets/direct-upload-tickets、OSS 直传、/api/assets/objects/confirm,长期状态只保存 assetObjectId/generated-* 引用;运行时图片用 ResolvedAssetImage 换签。
  • 验证:文档模式 sourceAssetIds 为平台资产 id草稿中不出现 data:;图片和音乐字段为平台 generated 引用或 null。
  • 关联:docs/prd/AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.mdsrc/services/visual-novel-creation/visualNovelAssetClient.ts

视觉小说 VN-13 交接时不要再回头找旧迁移方案

  • 现象:接手视觉小说的人容易重新打开旧 TXT 迁移文档,把“外部平台工程迁入”误当成当前实现目标。
  • 原因:视觉小说历史资料里保留了很多迁移阶段的讨论,而当前真正的实现口径已经收口到 PRD、表目录、Prompt 工具说明、实现收口文档和负向扫描报告。
  • 处理:维护视觉小说时优先看 AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.mdSPACETIMEDB_TABLE_CATALOG.mdVISUAL_NOVEL_PROMPT_AND_LLM_TOOLS_VN03_2026-05-05.mdVISUAL_NOVEL_IMPLEMENTATION_HANDOFF_2026-05-07.mdVISUAL_NOVEL_HANDOFF_AND_MAINTENANCE_2026-05-07.mdVN11_NEGATIVE_SCAN_REPORT_2026-05-07.md
  • 验证:新开发者只读这组文档即可继续维护,不需要把旧 TXT 迁移方案重新当作编码依据。
  • 关联:docs/prd/AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.mddocs/technical/VISUAL_NOVEL_IMPLEMENTATION_HANDOFF_2026-05-07.mddocs/experience/VISUAL_NOVEL_HANDOFF_AND_MAINTENANCE_2026-05-07.md

视觉小说公开广场不要触发登录刷新

  • 现象:未登录用户进入平台公开广场或从推荐流读取视觉小说公开作品时,前端可能先尝试 /api/auth/refresh,失败后再读取公开列表,导致无意义的鉴权噪声或 401 状态刷新。
  • 原因:公开只读接口如果复用默认 requestJson 选项,缺少 access token 时会先走静默 refresh。
  • 处理:视觉小说公开广场列表使用 skipAuth: trueskipRefresh: true;鉴权 mutation 仍保持默认鉴权链路。
  • 验证:执行 src/services/visual-novel-runtime/visualNovelRuntimeClient.test.ts,确认 /api/runtime/visual-novel/gallery 请求携带 skipAuth / skipRefresh,而 run、重生成和存档 mutation 仍走受保护路由。
  • 关联:src/services/visual-novel-runtime/visualNovelRuntimeClient.tsdocs/prd/AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.md

创作 Tab 语义迁移后,旧“新建作品”测试要改看智能创作首页

  • 现象:把 create 从旧创作中心切到 CreativeAgentHome 后,旧测试仍尝试在创作页找“新建作品”类型卡,导致用例失败或定位不到元素。
  • 原因:产品语义已经变成“创作 = 智能创作首页,草稿 = 旧作品架”,但测试夹具和 helper 还沿用旧入口。
  • 处理:把这类测试改成验证智能创作首页、快捷胶囊、抽屉与草稿 Tab同时给 useRpgEntryLibraryDetail 这类恢复路径补上 setPlatformTabToDraft
  • 验证:定向 vitesteslinttypecheckcheck:encoding 都通过。
  • 关联:src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsxsrc/components/rpg-entry/useRpgEntryAgentDraftRestore.test.tsxsrc/components/rpg-entry/useRpgEntryLibraryDetail.ts

server-rs 默认 cargo build 不能等同于构建 SpacetimeDB 模块

  • 现象:在 server-rs 下无参数 cargo build 期望同时构建 spacetime-module,导致链接或构建范围误判。
  • 原因workspace default-members 当前只包含 crates/api-serverSpacetimeDB module 有独立构建/发布方式。
  • 处理:默认 Rust 构建只覆盖原生 api-server;模块产物继续走 spacetime build / publish / bindings 生成流程。
  • 验证:查看 server-rs/Cargo.toml default-members并按相关 SpacetimeDB 文档执行模块构建。
  • 关联:server-rs/Cargo.tomldocs/technical/RUST_WORKSPACE_DEFAULT_BUILD_SCOPE_FIX_2026-04-25.md

Rust 构建不要让不可用的 sccache 阻断 rustc

  • 现象Cargo 报 could not execute process sccache ... rustc.exe -vV (never executed),真实 rustc -Vv 可以执行,但构建在调用包装器时失败。
  • 原因:环境或 Jenkinsfile 设置了 RUSTC_WRAPPER=sccache,但当前 Windows/Linux agent 上没有可执行的 sccache,或 PATH 中的 sccache shim 损坏。
  • 处理:本地临时排障可执行 Remove-Item Env:RUSTC_WRAPPER -ErrorAction SilentlyContinue 后重跑 Cargo生产流水线必须先实际执行 sccache --version,失败时移除 RUSTC_WRAPPER 并回退到直接 rustc
  • 验证:rustc -Vv 能输出版本;cargo 不再尝试调用不可用的 sccacheJenkins 日志出现“未找到可用 sccache改用 rustc 直接构建”后仍继续真实构建。
  • 关联:jenkins/Jenkinsfile.production-stdb-module-builddocs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md

生产发布入口不要沿用旧 Jenkinsfile / 一体化脚本

  • 现象:部署、回滚或 Jenkins Job 重建时参考旧发布文档,导致 systemd、Nginx、SpacetimeDB 自托管和生产包拆分不一致。
  • 原因:旧 Jenkins / 旧本地远端部署脚本文档仍作为历史经验保留。
  • 处理:生产相关操作先看 PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md,再按需追溯旧文档。
  • 验证:发布链路使用当前 deploy/systemddeploy/nginxscripts/deployjenkins/Jenkinsfile.production-*
  • 关联:docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md

个人任务 scope 不得扩成 work/site/module

  • 现象:个人任务配置为 work / site / module 后进度串桶或静默按 0 处理。
  • 原因:首版个人任务只支持用户维度,非 user scope 会造成任务进度读取语义错误。
  • 处理Admin 任务配置页不展示范围选择,保存时固定 scopeKind: 'user'API 和领域构造层拒绝非 User
  • 验证:非 user scope 返回错误;相关测试覆盖 Site / Module / Work 被拒绝。
  • 关联:docs/technical/RUNTIME_PROFILE_TASK_SCOPE_2026-05-04.mddocs/technical/ANALYTICS_DATE_DIMENSION_IMPLEMENTATION_2026-05-04.md