1
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-05-11 20:57:16 +08:00
81 changed files with 3410 additions and 132 deletions

View File

@@ -67,9 +67,11 @@ HTTP status server error (503 Service Unavailable)
远端 `xushi-p4wfr` 挂起期间,抓大鹅本地体验应使用本地 SpacetimeDB
```powershell
spacetime --root-dir=server-rs/.spacetimedb/local start --edition standalone --listen-addr 127.0.0.1:3101
npm run dev:rust
$env:GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET="codex-local-bootstrap-secret-20260501"
spacetime --root-dir=server-rs/.spacetimedb/local publish xushi-p4wfr --server http://127.0.0.1:3101 --module-path server-rs/crates/spacetime-module -c=on-conflict --yes
Push-Location server-rs
spacetime publish xushi-p4wfr --server http://127.0.0.1:3101 --module-path crates/spacetime-module -c=on-conflict --yes
Pop-Location
```
再让 Rust API 指向本地库:

View File

@@ -115,9 +115,9 @@ Match3DWorkProfile / PlatformMatch3DGalleryCard
3. 使用 Three.js `GLTFLoader.parseAsync` 解析 GLB 字节,并按物品类型缓存模板。
4. 场内每个物品和备选栏预览都从模板 clone 独立对象,点击命中继续写入 `itemInstanceId`
5. 物理碰撞和边界仍沿用现有 `visualKey` 的程序化几何,生成 GLB 只替换视觉模型,不承接规则真相。
6. 模型缺失、读取失败或 WebGL 回退时,继续使用默认积木素材,不能阻断开局、点击、入槽或结算。
6. 模型缺失、读取失败或 WebGL 回退时,继续使用默认积木素材,不能阻断开局、点击、入槽或结算;调试模式下需要输出加载失败的 `itemTypeId`、模型来源和错误信息便于区分“资产没有传入”和“GLB 字节读取或解析失败”
结果页点击 `试玩` 时,前端必须把当前结果页可见的 `generatedItemAssets` 带入运行态启动入参。`PUT /api/runtime/match3d/works/{profileId}` 若因为并发或旧快照返回了缺少素材的 profile`Match3DResultView` 需要把当前 draft / profile 的素材重新合并到 `onStartTestRun(profile)`若历史草稿同时存在旧 `draft.generatedItemAssets` 和较新的 `profile.generatedItemAssets`,同 `itemId` 下以 profile 中已有的 `modelSrc` / `modelObjectKey` 补齐 draft不能让旧 draft 把模型状态覆盖回 `image_ready``PlatformEntryFlowShellImpl` 在渲染 `match3d-runtime` 时按 `run.profileId` 优先使用当前 `match3dProfile.generatedItemAssets`,只有 profileId 不匹配时才读取 `selectedPublicWorkDetail.generatedItemAssets`。推荐流内嵌正式运行态也必须走同一解析器;当推荐卡片摘要缺少素材时,启动前补读 `getMatch3DWorkDetail(profileId)`,把详情里的生成模型写入 `match3dProfile` 后再传给运行态。这样可以避免从公开详情页残留状态或推荐卡片旧摘要进入试玩 / 正式游戏时,把已生成草稿的 3D 模型覆盖成空列表。
结果页点击 `试玩` 时,前端必须把当前结果页可见的 `generatedItemAssets` 带入运行态启动入参。`PUT /api/runtime/match3d/works/{profileId}` 若因为并发或旧快照返回了缺少素材的 profile`Match3DResultView` 需要把当前 draft / profile 的素材重新合并到运行态 profile并在启动试玩前调用生成素材保存接口把当前可见的 `generatedItemAssets` 写回作品 profile不能只在内存里把素材补到 `onStartTestRun(profile)`。发布同理必须先落库当前素材,再调用 `publish_match3d_work`,否则公开推荐流和正式运行态只能读到旧 profile 快照,历史草稿尤其容易表现为结果页有 3D 模型、正式游戏仍是默认积木。若历史草稿同时存在旧 `draft.generatedItemAssets` 和较新的 `profile.generatedItemAssets`,同 `itemId` 下以 profile 中已有的 `modelSrc` / `modelObjectKey` 补齐 draft不能让旧 draft 把模型状态覆盖回 `image_ready``PlatformEntryFlowShellImpl` 在渲染 `match3d-runtime` 时按 `run.profileId` 优先使用当前 `match3dProfile.generatedItemAssets`,只有 profileId 不匹配时才读取 `selectedPublicWorkDetail.generatedItemAssets`。推荐流内嵌正式运行态也必须走同一解析器;当推荐卡片摘要缺少素材时,启动前补读 `getMatch3DWorkDetail(profileId)`,把详情里的生成模型写入 `match3dProfile` 后再传给运行态。这样可以避免从公开详情页残留状态或推荐卡片旧摘要进入试玩 / 正式游戏时,把已生成草稿的 3D 模型覆盖成空列表。
## 6. 自动保存与草稿恢复

View File

@@ -0,0 +1,27 @@
# 公开作品详情失效回首页修复
日期:`2026-05-11`
## 背景
直接访问 `/works/detail?work=<公开作品号>` 时,如果作品已经删除、下架或当前公开列表无法命中该作品,统一作品详情会先进入 `work-detail` 阶段。此前该阶段在没有 `selectedPublicWorkDetail` 时不会渲染任何内容;用户关闭“作品不存在或已下架”的提示后,页面可能只剩空白区域。
## 修复
1. `resolveWorkNotFoundRecoveryAction(...)` 覆盖 `/works/detail`、拼图公开详情和视觉小说公开详情,并复用运行态深链失效的回首页策略。
2. 拼图公开详情、拼图运行态启动和拼图详情页读取的 `404/NOT_FOUND` 分支改为统一走公开作品失效恢复逻辑。
3. 直接打开 `/works/detail?work=...` 的搜索失败分支会清理详情态、运行态临时数据,切回首页并清掉 URL query。
4. `work-detail` 阶段在详情数据为空时渲染轻量读取态,避免异步间隙或异常分支出现纯白屏。
## 验证
- `npm run test -- src/routing/runtimeNotFoundRecovery.test.ts`
- `npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "direct missing public work detail alert returns to platform home"`
- `npm run typecheck`
- `npm run check:encoding -- src/routing/runtimeNotFoundRecovery.ts src/routing/runtimeNotFoundRecovery.test.ts src/components/platform-entry/PlatformEntryFlowShellImpl.tsx src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx docs/technical/PUBLIC_WORK_DETAIL_NOT_FOUND_RECOVERY_2026-05-11.md`
## 关联文件
1. `src/routing/runtimeNotFoundRecovery.ts`
2. `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
3. `src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx`

View File

@@ -4,6 +4,7 @@
## 文档列表
- [PUBLIC_WORK_DETAIL_NOT_FOUND_RECOVERY_2026-05-11.md](./PUBLIC_WORK_DETAIL_NOT_FOUND_RECOVERY_2026-05-11.md):记录直接访问公开作品详情深链时作品不存在或已下架的回首页修复,避免关闭提示后停在 `work-detail` 空状态白屏。
- [CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md](./CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md):冻结儿童动作识别互动玩法 Demo 固定热身关的开发落地规格,覆盖横屏展示、摄像头背景虚化、角色剪影、绿色圆环 2 秒保持、动作教学、当前会话内空间边界记录和后续关卡安全暂停规则。
- [RUNTIME_INPUT_DEVICE_ABSTRACTION_2026-05-10.md](./RUNTIME_INPUT_DEVICE_ABSTRACTION_2026-05-10.md)记录运行态输入设备抽象层明确鼠标、触控、mocap 等设备统一归一为通用拖拽语义,玩法组件只负责解释目标和落点。
- [RUST_WORKSPACE_DEPENDENCY_CONSOLIDATION_2026-05-07.md](./RUST_WORKSPACE_DEPENDENCY_CONSOLIDATION_2026-05-07.md):记录 `server-rs` Cargo 依赖集中配置口径,第三方版本和 workspace 内部 crate path 统一维护在根 `server-rs/Cargo.toml`,成员 crate 只保留 feature/optional 差异;同时冻结 `shared-contracts` 不得反向依赖 `platform-*`,避免 SpacetimeDB 模块发布时拉入 `wasm-bindgen`
@@ -79,7 +80,7 @@
- [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md):冻结 SpacetimeDB 表结构变更约束、自动迁移可接受范围、冲突后的系统行为,以及保留旧数据的增量迁移流程;凡涉及 `spacetime publish`、表字段调整或 `migration.rs` 对齐时优先参考。
- [PRODUCT_NAMING_BAIMENG_RENAME_2026-05-01.md](./PRODUCT_NAMING_BAIMENG_RENAME_2026-05-01.md):冻结当前对外中文命名,产品展示名统一为“百梦”,消费单位为“光点”,公开账号标识为“百梦号”,创作侧称谓为“百梦主”。
- [SPACETIMEDB_CLOUD_CONFIG_REMOVAL_2026-05-02.md](./SPACETIMEDB_CLOUD_CONFIG_REMOVAL_2026-05-02.md):记录旧云端 SpacetimeDB 配置、发布脚本和默认文档口径的移除结果,冻结后续仅使用本地或显式 `SERVER_URL` 的运维规则。
- [SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md](./SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md):记录本地 standalone 启动时报 `mismatched database identity` root-dir/replica 数据残留根因、备份重建步骤和脚本诊断口径。
- [SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md](./SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md):记录本地 standalone 启动时报 `mismatched database identity`数据目录/replica 数据残留根因、备份重建步骤和脚本诊断口径。
- [AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md](./AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md):记录远端库挂起导致认证快照同步和抓大鹅创作失败的根因、认证同步非阻断修复、`/api/creation` Vite 代理补齐和本地 SpacetimeDB 可跑链路。
- [LLM_MODEL_ROUTING_RPG_AND_CREATION_2026-04-30.md](./LLM_MODEL_ROUTING_RPG_AND_CREATION_2026-04-30.md):冻结 RPG 运行时剧情推理使用 `doubao-seed-character-251128``/chat/completions`,以及所有模板创作大模型推理使用 `deepseek-v3-2-251201``/responses`
- [PROFILE_INVITE_CODE_REGISTRATION_AND_ADMIN_2026-04-30.md](./PROFILE_INVITE_CODE_REGISTRATION_AND_ADMIN_2026-04-30.md):冻结邀请码从“我的 Tab 填写”迁到注册环节的前后端边界、`profile_invite_code.metadata_json` 表结构扩展、管理员邀请码虚拟主体和奖励规则。
@@ -113,11 +114,11 @@
- [RPG_SCENE_ACT_PREVIEW_BOOTSTRAP_FIX_2026-04-30.md](./RPG_SCENE_ACT_PREVIEW_BOOTSTRAP_FIX_2026-04-30.md):记录编辑器幕预览卡在“正在载入这一幕”时的启动态根因,收口预览本地运行态装配与禁持久化首段 story 注入。
- [PUZZLE_RESULT_AUTOSAVE_AND_TAG_GATE_FIX_2026-04-28.md](./PUZZLE_RESULT_AUTOSAVE_AND_TAG_GATE_FIX_2026-04-28.md):记录拼图结果页名称与标签编辑自动保存、发布门槛统一到 `3~6` 标签,以及前端发布校验不再被旧 session blocker 卡死的修复口径。
- [WORK_AUTHOR_ID_RESOLUTION_2026-04-30.md](./WORK_AUTHOR_ID_RESOLUTION_2026-04-30.md):记录作品作者以 `owner_user_id` 为真相源API 按用户 ID 解析最新昵称与公开用户码,历史 `author_display_name` 仅作为兼容回退。
- [SPACETIMEDB_START_SH_EARLY_EXIT_DIAGNOSTICS_2026-04-27.md](./SPACETIMEDB_START_SH_EARLY_EXIT_DIAGNOSTICS_2026-04-27.md)记录发布包 `start.sh` 只输出“SpacetimeDB 进程在就绪前退出”时的诊断补强,启动失败或超时时自动回显 `logs/spacetimedb.log``server ping`、端口监听和 root-dir 相关进程
- [SPACETIMEDB_START_SH_EARLY_EXIT_DIAGNOSTICS_2026-04-27.md](./SPACETIMEDB_START_SH_EARLY_EXIT_DIAGNOSTICS_2026-04-27.md)历史事故记录,保留旧发布包 `start.sh` 只输出“SpacetimeDB 进程在就绪前退出”时的诊断补强;该文档不再作为当前发布或人工排障依据
- [RPG_AND_AGENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md](./RPG_AND_AGENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md):记录 RPG 运行时 NPC 聊天、RPG/自定义世界 Agent 与大鱼 Agent 从“拼完整 SSE 字符串后一次性返回”改为 `mpsc + Sse<Event>` 真流式输出的后端落地口径。
- [SPACETIMEDB_START_SH_ROOT_OWNER_FALSE_POSITIVE_FIX_2026-04-27.md](./SPACETIMEDB_START_SH_ROOT_OWNER_FALSE_POSITIVE_FIX_2026-04-27.md)记录发布包 `start.sh` root-dir 占用检测把 `grep -F .../.spacetimedb` 误判为 SpacetimeDB 实例的根因、脚本修复和现场处理方式
- [SPACETIMEDB_START_SH_ROOT_OWNER_FALSE_POSITIVE_FIX_2026-04-27.md](./SPACETIMEDB_START_SH_ROOT_OWNER_FALSE_POSITIVE_FIX_2026-04-27.md)历史事故记录,保留旧发布包 `start.sh` 占用检测把 `grep -F .../.spacetimedb` 误判为 SpacetimeDB 实例的根因;该文档不再作为当前发布或人工排障依据
- [RPG_BATTLE_HEALTHBAR_AND_ACTION_PRESENTATION_FIX_2026-04-26.md](./RPG_BATTLE_HEALTHBAR_AND_ACTION_PRESENTATION_FIX_2026-04-26.md):记录 RPG 战斗血条安全锚点、服务端战斗回包前端短表现,以及 `battle_use_skill` 指定技能兜底结算的修复口径。
- [SPACETIMEDB_START_SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md](./SPACETIMEDB_START_SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md)记录发布包 `start.sh` 执行 `spacetime publish` 遇到 `403 Forbidden` 的身份根因`.spacetimedb/` root-dir 隔离修复和排查步骤
- [SPACETIMEDB_START_SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md](./SPACETIMEDB_START_SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md)历史事故记录,保留旧发布包执行 `spacetime publish` 遇到 `403 Forbidden` 的身份根因;当前人工命令禁止使用 `spacetime --root-dir`CI/CD 脚本内部受控用法除外
- [SPACETIMEDB_TABLE_CATALOG.md](./SPACETIMEDB_TABLE_CATALOG.md):持续维护当前 SpacetimeDB 表目录,按领域说明每张表的作用、字段结构、索引和常用 `spacetime sql` 查询模板。
- [RPG_OPENING_SCENE_ACT_IMAGE_PRESENTATION_SYNC_2026-04-26.md](./RPG_OPENING_SCENE_ACT_IMAGE_PRESENTATION_SYNC_2026-04-26.md):记录开局场景与普通场景复用同一场景展示解析服务,修复列表幕缩略图和详情幕背景预览图片不一致的问题。
- [FRONTEND_FIRST_LOAD_PERFORMANCE_FIX_2026-04-26.md](./FRONTEND_FIRST_LOAD_PERFORMANCE_FIX_2026-04-26.md):记录网站启动后首次加载约三分钟的前端根因,收口 `RouteImageReadyGate` 首屏图片门控和 Vite dev server 无关文件监听范围。

View File

@@ -26,6 +26,12 @@
- mocap 光标按 60Hz 插值更新 UI 位置,并在拖拽中用插值后的当前点持续驱动输入层,避免输入包帧率低或抖动时出现明显跳变。
- 合并大块由拼图运行态把手部坐标命中到任一成员拼块;本地拼图运行时再按 `mergedGroupId` 执行整组平移。
## 调试模式
前端全局调试模式统一通过 `src/config/debugMode.ts` 判断。默认跟随 Vite 开发态:`import.meta.env.DEV` 为真时开启,生产构建默认关闭;如需显式覆盖,可设置 `VITE_DEBUG_MODE=true``VITE_DEBUG_MODE=false`
拼图运行态的 mocap 调试面板只在全局调试模式下渲染。面板默认折叠,只保留一行连接状态,展开后才显示动作、手势、解析告警和原始包预览,避免开发诊断信息遮挡拼图棋盘和底部操作。
## 接入规则
新玩法或新设备接入时遵循以下边界:

View File

@@ -114,7 +114,7 @@ npm run dev:rust:logs -- --follow
日志提取规则:
1. SpacetimeDB 模块日志以 `spacetime --root-dir=server-rs/.spacetimedb/local logs <database>`唯一提取入口,脚本不直接读取内部日志文件结构。
1. SpacetimeDB 模块日志以 `spacetime logs <database> --server <实际本地 server>``npm run dev:rust:logs` 为提取入口,脚本不直接读取内部日志文件结构。
2. 默认读取 `spacetime.local.json``database` 字段,默认 server 为 `http://127.0.0.1:3101`
3. 默认输出到 `logs/spacetime/<database>-<timestamp>.log`,并通过 `tee` 同步显示在终端。
4. `--follow` 仅用于本地追踪,会持续追加到同一个输出文件;停止时用 `Ctrl+C`
@@ -125,8 +125,8 @@ npm run dev:rust:logs -- --follow
2. `spacetime list --server http://127.0.0.1:3101` 应能看到 `spacetime.local.json` 中的库名;若没有,执行 `spacetime publish <本地数据库名> --server http://127.0.0.1:3101 --module-path server-rs/crates/spacetime-module --build-options="--debug" -c=on-conflict --yes`
3. 发布库名与 `GENARRATIVE_SPACETIME_DATABASE` 不一致时,`/api/runtime/custom-world-gallery` 会从 Rust `api-server` 返回 `502`,前端首页只能展示空态或错误提示,无法自行修复。
4. 如果 Vite 输出 `/api/auth/refresh``/api/auth/login-options``/api/runtime/custom-world-gallery``ECONNREFUSED`,先确认当前脚本是否已经打印 `等待 api-server 就绪` 并通过;正常情况下 Vite 只会在 `/healthz` 可访问后启动,不应再因为 Rust 监听未完成而代理失败。
5. 如果 `spacetime server ping` 打印 `Server could not be reached (502 Bad Gateway)`,即使命令退出码为 `0` 也不能直接视为已就绪;本地脚本会继续探测 `/v1/ping`。若 `/v1/ping` 返回 `200`,说明 standalone 已经可用,可以继续发布模块;若 `/v1/ping` 也失败,脚本会继续等待新启动实例,或在 root-dir 已被其他实例占用时输出占用进程。
6. 如果本地 `spacetime publish` 显示 `401` 无权限,且确认本地开发数据可以丢弃,可执行 `spacetime --root-dir=server-rs/.spacetimedb/local server clear` 清除本地 SpacetimeDB 数据库后重新发布。重新发布时日志应表现为创建新的数据库,而不是更新旧数据库;如果仍显示更新旧库或继续无权限,说明 root-dir、库名或 CLI 身份仍未对齐。
5. 如果 `spacetime server ping` 打印 `Server could not be reached (502 Bad Gateway)`,即使命令退出码为 `0` 也不能直接视为已就绪;本地脚本会继续探测 `/v1/ping`。若 `/v1/ping` 返回 `200`,说明 standalone 已经可用,可以继续发布模块;若 `/v1/ping` 也失败,脚本会继续等待新启动实例,或在本地数据目录已被其他实例占用时输出占用进程。
6. 如果本地 `spacetime publish` 显示 `401` 无权限,且确认本地开发数据可以丢弃,先停止本地 SpacetimeDB再备份或删除 `server-rs/.spacetimedb/local/data` 后重新运行 `npm run dev`。重新发布时日志应表现为创建新的数据库,而不是更新旧数据库;如果仍显示更新旧库或继续无权限,说明数据目录、库名或 CLI 身份仍未对齐。除 CI/CD 脚本内部受控用法外,人工清理不要使用 `spacetime --root-dir`
7. Windows / Git Bash 下读取 `spacetime.pid``dev-rust-spacetime-url` 时,如果文件正被 SpacetimeDB 更新,不能用 `tr/head/xargs` 管道直接读;脚本使用 Node 读取并短重试,避免出现 `tr: read error: Device or resource busy` 后直接中断。
编译警告治理:
@@ -166,12 +166,12 @@ npm run deploy:rust:remote
5. 执行 `cargo build -p spacetime-module --release --target wasm32-unknown-unknown --manifest-path server-rs/Cargo.toml`,并把 `spacetime_module.wasm` 复制到目标目录。
6. 把仓库根目录的 `.env``.env.local` 分别复制到目标目录根部和目标目录的 `web/` 下;复制后统一移除 UTF-8 BOM 与 CRLF并把 `GENARRATIVE_SPACETIME_DATABASE` 覆盖为本次 `--database` 参数,避免 Jenkins 工作区里残留的旧 `.env.local` 覆盖发布包目标库。
7. 在目标目录写入 `web-server.mjs`,用于托管 `web/``web/admin/`;其中 `/admin` 跳转到 `/admin/``/admin/` 提供后台 SPA`/admin/api/*``/api/*``/generated-*``/healthz` 反代到本包内的 `api-server`
8. 在目标目录写入 `start.sh``stop.sh``start.sh` 会先按 `KEY=value` 子集加载发布目录根部的 `.env``.env.local`,兼容 UTF-8 BOM 与 CRLF再回退到构建时通过 `--database``--api-port``--web-host``--web-port``--spacetime-host``--spacetime-port` 写入的默认值,其中 Web 默认只监听 `127.0.0.1`;并默认导出 `NO_COLOR=1``CARGO_TERM_COLOR=never`,避免 ANSI 控制码写入日志文件;同时按 Ubuntu 发布环境使用发布目录内 `.spacetimedb/` 作为 root-dir不再额外设置 `--data-dir`,启动前先执行 `sync_ubuntu_spacetime_install`,优先从 `/usr/.local/share/spacetime/bin/<version>/spacetimedb-cli``$HOME/.local/share/spacetime/bin/<version>/spacetimedb-cli` 同步到 `.spacetimedb/bin/current/spacetimedb-cli`,当前线上 `spacetime` 入口为 `/usr/local/bin/spacetime`;启动参数为 `spacetime --root-dir ./.spacetimedb start --edition standalone --listen-addr <host>:<port>`,探活必须确认 `server ping` 输出包含 `Server is online:`普通启动先无清库发布,若 publish 输出可判定为 schema 冲突,则自动导出旧库、清库发布新 wasm、导入回灌如果以 `--clear-database` 启动,则内部 `spacetime publish` 会追加 `-c=on-conflict`,代表人工确认清库,不触发自动回灌。
8. 在目标目录写入 `start.sh``stop.sh``start.sh` 会先按 `KEY=value` 子集加载发布目录根部的 `.env``.env.local`,兼容 UTF-8 BOM 与 CRLF再回退到构建时通过 `--database``--api-port``--web-host``--web-port``--spacetime-host``--spacetime-port` 写入的默认值,其中 Web 默认只监听 `127.0.0.1`;并默认导出 `NO_COLOR=1``CARGO_TERM_COLOR=never`,避免 ANSI 控制码写入日志文件;SpacetimeDB 启动、探活和发布由发布脚本内部统一编排。脚本内部如保留 `--root-dir`,只属于 CI/CD 或发布包受控用法,不作为人工命令模板。普通启动先无清库发布,若 publish 输出可判定为 schema 冲突,则自动导出旧库、清库发布新 wasm、导入回灌如果以 `--clear-database` 启动,则内部 `spacetime publish` 会追加 `-c=on-conflict`,代表人工确认清库,不触发自动回灌。
9. 默认执行 `scp -r -i ~\.ssh\dsk.pem build/<timestamp> ubuntu@82.157.175.59:/home/ubuntu/genarrative/` 上传发布包。
SpacetimeDB database 名称必须匹配 `^[a-z0-9]+(-[a-z0-9]+)*$`:只能使用小写字母、数字,并用单个短横线分隔;大写字母、点号、下划线、首尾短横线和连续短横线都会触发 `spacetime publish``invalid characters in database name`。发布包构建脚本和 `start.sh` 都会提前拦截这类非法名称。
发布包构建日志会输出 `SpacetimeDB 发布数据库: <database>`;目标服务器执行 `start.sh` 时会在发布前输出最终加载后的 `database/server/root-dir`,用于确认 `.env.local` 或 Jenkins 参数覆盖后的实际发布目标。
发布包构建日志会输出 `SpacetimeDB 发布数据库: <database>`;目标服务器执行 `start.sh` 时会在发布前输出最终加载后的 `database/server/数据目录或脚本运行目录`,用于确认 `.env.local` 或 Jenkins 参数覆盖后的实际发布目标。
发布包结构:
@@ -225,8 +225,8 @@ cd build/<timestamp>
5. 自动迁移导出旧库时优先读取 `deploy-state/migration-bootstrap-secret.previous.txt`,导入新库时读取当前发布包 `migration-bootstrap-secret.txt`Jenkins 部署脚本会在覆盖发布包前保存旧密钥。该快照属于部署状态,不放入 `run/`,避免启停 hook 通过 `sudo` 运行后把部署阶段要写的文件变成 root 私有。手工覆盖发布包时,也应在覆盖前保留旧模块的引导密钥,否则旧库导出可能无法授权。
6. 自动迁移 JSON 默认写入发布目录下 `database-migrations/<database>/`;可通过 `GENARRATIVE_SPACETIME_MIGRATION_DIR` 改写。该目录属于运行态,不应被 Jenkins 覆盖部署删除。
7. 只有显式执行 `./start.sh --clear-database` 才追加 `-c=on-conflict`,该模式代表人工确认清库,不执行导出和回灌。
8. `start.sh` 会先复用已经按目标地址就绪的 SpacetimeDB如果同一个 `.spacetimedb/` root-dir 已被其他未就绪实例占用,则只输出命令名为 `spacetime``spacetimedb-cli` 且命令行包含当前 root-dir 的真实占用进程并失败,避免把排查用的 `grep` / `awk` 误判为 SpacetimeDB 实例。
9. 如果 `spacetime publish``403 Forbidden`,优先确认 `spacetime --root-dir ./.spacetimedb login show` 输出的身份是否有权更新目标库`--clear-database` 不能绕过身份授权
8. `start.sh` 会先复用已经按目标地址就绪的 SpacetimeDB如果同一个 `.spacetimedb/` 运行目录已被其他未就绪实例占用,则只输出真实占用进程并失败,避免把排查用的 `grep` / `awk` 误判为 SpacetimeDB 实例。
9. 如果 `spacetime publish``403 Forbidden`,优先确认 `spacetime login show` 输出的身份是否有权更新目标库,并确认 `GENARRATIVE_SPACETIME_DATABASE` / `GENARRATIVE_SPACETIME_SERVER_URL` 未指向错误环境;`--clear-database` 不能绕过身份授权。除 CI/CD 脚本内部受控用法外,人工排障不要使用 `spacetime --root-dir`
10. 当前脚本是单目录进程启动方案,不替代生产 systemd、Nginx、TLS、日志轮转与守护进程配置。
11. 如只需要本地生成发布包,可传 `--skip-upload` 跳过默认 scp 上传。

View File

@@ -17,7 +17,8 @@
5. 需要关闭 default features 的依赖,应优先在 workspace 根依赖中声明;成员 crate 不再重复覆盖同一项。
6. `module-assets` 这类有默认服务端 feature 的领域 crate在 workspace 根内按 `default-features = false` 维护;需要服务端 OSS/HTTP 能力的 adapter crate 显式启用 `features = ["server-service"]`
7. `shared-contracts` 只能承载前后端公开 DTO 和轻量枚举,禁止直接依赖 `platform-*` 服务实现 crate需要把平台实现响应转换为公开 DTO 时,转换函数放在 `api-server` 等 adapter 层。
8. `spacetime-module` 的传递依赖不能包含 `reqwest``web-sys``js-sys``wasm-bindgen` 等 Web/HTTP 客户端链路;发布前可用 `cargo tree -i wasm-bindgen --manifest-path server-rs/Cargo.toml -p spacetime-module --target wasm32-unknown-unknown` 排查
8. 面向 SpacetimeDB WASM 的依赖链不得隐式启用原生 HTTP / OSS / Web 平台依赖;例如 `shared-contracts``assets` 模块通过不依赖 `platform-oss``oss-contracts` feature 暴露给 `api-server``spacetime-module` 路径只消费关闭默认 feature 后的纯 DTO 子集
9. `spacetime-module` 的传递依赖不能包含 `reqwest``web-sys``js-sys``wasm-bindgen` 等 Web/HTTP 客户端链路;发布前可用 `cargo tree -i wasm-bindgen --manifest-path server-rs/Cargo.toml -p spacetime-module --target wasm32-unknown-unknown` 排查。
## 3. 本次收敛范围
@@ -56,7 +57,7 @@ npm.cmd run check:encoding -- docs/technical/RUST_WORKSPACE_DEPENDENCY_CONSOLIDA
若仅改 Cargo 依赖配置且未触碰 API smoke 相关代码,不强制启动 `npm run api-server`;若后续改动同时涉及 API 路由、SpacetimeDB facade 或运行时行为,仍按 `AGENTS.md` 和 DDD 文档执行后端 smoke。
## 6. SpacetimeDB 模块依赖边界补充
## 6. SpacetimeDB WASM 依赖边界
2026-05-11 本地重置 SpacetimeDB 并重新发布 `xushi-p4wfr` 时,`spacetime publish` 在 Rust 编译成功后报 `wasm-bindgen detected`。排查命令显示链路为:
@@ -66,6 +67,8 @@ spacetime-module -> module-runtime -> shared-contracts -> platform-oss -> reqwes
根因是 `shared-contracts` 为了复用 OSS 直传/读签名返回类型,直接依赖了 `platform-oss`。这违反 DDD 分层边界:契约 crate 不能依赖平台副作用实现,否则所有引用契约的纯领域和 SpacetimeDB 模块都会被迫拉入 HTTP client。
`spacetime publish` 会构建 `spacetime-module``wasm32-unknown-unknown` 目标。这个目标不能包含 `wasm-bindgen`,也不应通过 DTO crate 间接拉入 `reqwest``web-sys` 或浏览器 WebAssembly 平台依赖。
修正口径:
1. `shared-contracts::assets` 定义独立的公开 DTO 和 `DirectUploadObjectAccess` 轻量枚举。
@@ -73,11 +76,16 @@ spacetime-module -> module-runtime -> shared-contracts -> platform-oss -> reqwes
3. `api-server::assets` 负责把 `platform_oss::OssPostObjectResponse` / `OssSignedGetObjectUrlResponse` 转成 `shared-contracts` DTO。
4. 后续新增外部平台能力时,重复使用这个边界:平台 crate 不得被 `shared-contracts``module-*``spacetime-module` 反向依赖。
最小验证
已验证的排查命令
```powershell
cargo tree -i wasm-bindgen --manifest-path server-rs\Cargo.toml -p spacetime-module --target wasm32-unknown-unknown
cargo tree -i wasm-bindgen --manifest-path server-rs\crates\spacetime-module\Cargo.toml --target wasm32-unknown-unknown
cargo tree --manifest-path server-rs\crates\spacetime-module\Cargo.toml --target wasm32-unknown-unknown | Select-String -Pattern 'wasm-bindgen|platform-oss|reqwest'
cargo check -p spacetime-module --manifest-path server-rs\Cargo.toml --target wasm32-unknown-unknown
cargo check -p shared-contracts --manifest-path server-rs\Cargo.toml
cargo check -p api-server --manifest-path server-rs\Cargo.toml
spacetime publish xushi-p4wfr --server local --module-path server-rs\crates\spacetime-module --build-options="--debug" -c=on-conflict --yes
```
若反向树显示 `reqwest -> platform-oss -> shared-contracts -> module-* -> spacetime-module`,优先检查新增的 `shared-contracts` 或领域 crate 依赖是否忘记关闭默认 feature`shared-contracts` feature 是否错误依赖了平台实现 crate。原生 `api-server` 需要资产上传契约时,应在自身 `Cargo.toml` 显式启用 `shared-contracts``oss-contracts` feature而不是让 workspace 根依赖默认启用。

View File

@@ -39,4 +39,4 @@ GENARRATIVE_SPACETIME_TOKEN
1. 新增 SpacetimeDB 运维脚本时,不允许把云端服务写成默认值。
2. 文档中的验证命令统一使用 `npm run api-server`
3. 如果某次任务需要连接非本地 SpacetimeDB必须在文档和验证记录中写清楚实际 `SERVER_URL`、数据库名和 root-dir
3. 如果某次任务需要连接非本地 SpacetimeDB必须在文档和验证记录中写清楚实际 `SERVER_URL`、数据库名和身份来源;除 CI/CD 脚本内部受控用法外,不再把 `--root-dir` 写入人工命令

View File

@@ -16,17 +16,17 @@ error starting database: failed to init replica 1 for <new-database-identity>: m
2. `replica 1` 的持久化数据仍带有旧库 `c20037fcfaac4e5c4b1f492f026a4f6119a98f56319b77f21ef021ededf8b7ae`
3. SpacetimeDB 因同一个副本目录中 identity 不一致而拒绝继续启动。
这不是 Rust 编译错误,也不是 `api-server` 的 token 错误。只要错误来自 `server-rs/.spacetimedb/local/.../spacetime-standalone.log`,优先按本地 root-dir 数据目录污染处理。
这不是 Rust 编译错误,也不是 `api-server` 的 token 错误。只要错误来自 `server-rs/.spacetimedb/local/.../spacetime-standalone.log`,优先按本地 SpacetimeDB 数据目录污染处理。
## 2. 根因
`spacetime start --edition standalone` 会在同一个 `--root-dir`保存控制库、程序字节、WAL 与 replica 数据。当前仓库默认本地 root-dir 是:
`spacetime start --edition standalone` 会在本地数据目录中保存控制库、程序字节、WAL 与 replica 数据。当前仓库默认本地数据目录是:
```text
server-rs/.spacetimedb/local
server-rs/.spacetimedb/local/data
```
当这个目录曾经启动并发布过旧 database identity之后又用同一个 root-dir 初始化或发布到另一个 database identity 时,可能出现:
当这个目录曾经启动并发布过旧 database identity之后又用同一个数据目录初始化或发布到另一个 database identity 时,可能出现:
1. `control-db` 记录的是新库。
2. `data/replicas/1` 里仍残留旧库 WAL 或快照。
@@ -36,8 +36,8 @@ server-rs/.spacetimedb/local
1. 不在脚本里默认删除 `.spacetimedb` 数据,避免误删本地开发数据。
2. 如果只是本地开发库且数据可丢弃,优先备份后重建 `data` 目录。
3. 如果数据必须保留,不要清理目录;应改回创建旧库时使用的 database/root-dir或先导出迁移数据。
4. 本地 standalone root-dir 与其它部署目标是两条链路;不要通过切回 `server-node` 或 PostgreSQL 绕过。
3. 如果数据必须保留,不要清理目录;应改回创建旧库时使用的 database/server或先导出迁移数据。
4. 本地 standalone 数据目录与其它部署目标是两条链路;不要通过切回 `server-node` 或 PostgreSQL 绕过。
## 4. 本地可丢弃数据时的修复
@@ -73,10 +73,10 @@ npm run dev:rust
## 5. 需要保留数据时的处理
不要移动或删除 `server-rs/.spacetimedb/local/data`。先确认旧库 identity 对应的数据库名、root-dir 与发布命令,然后选择:
不要移动或删除 `server-rs/.spacetimedb/local/data`。先确认旧库 identity 对应的数据库名、server 与发布命令,然后选择:
1. 用旧库对应的 database/root-dir 重新启动。
2. 使用迁移导出脚本导出旧数据,再清理本地 root-dir 并导入到新库。
1. 用旧库对应的 database/server 重新启动或连接
2. 使用迁移导出脚本导出旧数据,再清理本地数据目录并导入到新库。
3. 如目标其实是其它已运行的 SpacetimeDB 服务,改用 `GENARRATIVE_SPACETIME_SERVER_URL` 指向该服务,避免误启动本地 standalone。
## 6. 脚本诊断

View File

@@ -7,6 +7,7 @@ Windows 本地执行 `npm run dev:rust` 或 `spacetime publish` 时,`spacetime
当本机 sccache server 状态损坏、client/server 通信异常或版本残留不一致时,可能出现:
```text
sccache: error: Timed out waiting for server startup. Maybe the remote service is unreachable?
sccache: error: failed to execute compile
sccache: caused by: Failed to send data to or receive data from server
sccache: caused by: Failed to read response header
@@ -15,9 +16,24 @@ sccache: caused by: failed to fill whole buffer
这类错误发生在 rustc wrapper 层,不能说明 SpacetimeDB module 代码本身编译失败。
## 2026-05-11 本机根因定位
本机 `cargo check -p api-server` 失败时Cargo 还没有进入业务 crate 编译,而是在读取 `server-rs/.cargo/config.toml` 后执行 `sccache rustc -vV` 探测编译器版本。失败的 stderr 会被写入 `server-rs/target/.rustc_info.json`,内容为 `Timed out waiting for server startup`
当前 PowerShell 环境设置了 `SCCACHE_OSS_BUCKET=genarrative-sccache``SCCACHE_OSS_ENDPOINT=https://oss-rg-china-mainland.aliyuncs.com``SCCACHE_OSS_KEY_PREFIX=genarrative`,且没有设置本地 `SCCACHE_DIR`。因此 sccache daemon 冷启动时会先初始化 OSS 远端缓存,并执行 `.sccache_check` 的读写检查;日志中可见 `Init oss cache ...``proxy(http://127.0.0.1:7897/) intercepts ...`,随后才出现 `server started, listening on 127.0.0.1:4226`
本次排查的结论是:冷启动失败主要发生在 sccache client 等待 daemon 启动的握手窗口内,而 daemon 启动又依赖 OSS/本机代理链路先完成缓存可读写检查。代理或 OSS 链路稍慢时Cargo 调用的 `sccache rustc -vV` 会先超时daemon 预热后直接执行同一条 `sccache rustc -vV` 又可能成功,所以这是冷启动/通道状态问题,不是 `api-server` 或 Rust 代码错误。
辅助证据:
1. `rustc -vV` 可直接输出版本,说明 Rust 工具链本身可用。
2. `tasklist` 曾只看到 `sccache --show-stats` 客户端进程,`netstat` 只出现到 `127.0.0.1:4226``SYN_SENT`,没有真正的 `LISTEN`,说明当时 client 正在等一个尚未成功监听的 daemon。
3. 在子进程中临时清掉 `SCCACHE_OSS_*` 并设置本地 `SCCACHE_DIR`sccache 退回本地磁盘缓存,日志显示 `Init disk cache ...``rustc -vV``sccache --show-stats` 均能完成。
4. `C:\Users\DSK\AppData\Roaming\Mozilla\sccache\config\config` 缺失只是非致命 warning本机实际配置来自环境变量。
## 本地开发处理
`scripts/dev-rust-stack.sh` 的 publish 阶段继续由 SpacetimeDB CLI 内部调用 Cargo并通过 `--build-options="--debug"` 使用 debug 构建参数。遇到 sccache 通信或 wrapper 失败时,本地排障仍优先绕过 wrapper 验证 rustc 本身可用。
`scripts/dev-rust-stack.sh` 的 publish 阶段继续由 SpacetimeDB CLI 内部调用 Cargo并通过 `--build-options="--debug"` 使用 debug 构建参数。遇到 sccache 冷启动超时时,优先保留 `sccache` wrapper并修复 sccache daemon 的启动等待时间;只有在排除 sccache 本身问题时,才临时绕过 wrapper 验证 rustc 本身可用。
该处理不修改 `server-rs/.cargo/config.toml`,也不删除本地 target 缓存。
@@ -29,13 +45,56 @@ sccache: caused by: failed to fill whole buffer
rustc -vV
```
如果只想绕过本次 Cargo 构建的 sccache wrapper可在 Git Bash 中执行
如果要保留 sccache 并修复冷启动等待时间,在 PowerShell 中创建或更新 sccache 默认配置
```powershell
$configDir = Join-Path $env:APPDATA "Mozilla\sccache\config"
New-Item -ItemType Directory -Force -Path $configDir | Out-Null
@(
"# Windows 本机 sccache 冷启动需要先完成 OSS 缓存读写检查。"
"# 拉长 client 等待 daemon 启动的时间,避免 Cargo 在 rustc -vV 阶段误判超时。"
"server_startup_timeout_ms = 60000"
) | Set-Content -Encoding UTF8 -Path (Join-Path $configDir "config")
```
随后清掉 Cargo 曾缓存的失败探测结果,并从冷启动验证:
```powershell
cd C:\proj\Genarrative\server-rs
sccache --stop-server
Remove-Item -Force target\.rustc_info.json -ErrorAction SilentlyContinue
cargo check -p api-server
```
注意:不要在另一个 `cargo` / `rustc` 仍在编译时执行 `taskkill /F /IM sccache.exe /T`。sccache 对 proc-macro crate 会显示 `Server sent UnhandledCompile` 并把请求转交给真实 rustc如果此时强杀 sccache client/server可能让 `serde_derive``spacetimedb-bindings-macro` 等 proc-macro 编译直接以 `sccache ... exit code: 1` 失败,而 stderr 里看不到真正的 Rust 诊断。这是排障动作打断编译,不是 `spacetime-module` 源码错误。
如果只想临时绕过本次 Cargo 构建的 sccache wrapper可在 Git Bash 中执行:
```bash
cd server-rs/crates/spacetime-module
RUSTC_WRAPPER= CARGO_BUILD_RUSTC_WRAPPER= cargo check --target=wasm32-unknown-unknown
```
PowerShell 原生 Cargo 的一次性 wrapper 绕过命令是:
```powershell
cd C:\proj\Genarrative\server-rs
cargo check -p api-server --config "build.rustc-wrapper=''"
```
如果需要验证是否为 OSS/代理冷启动问题,可只在当前 PowerShell 进程中切到本地缓存做对照:
```powershell
$env:SCCACHE_LOG = "debug"
$env:SCCACHE_ERROR_LOG = "C:\proj\Genarrative\logs\sccache-local-start-error.log"
$env:SCCACHE_DIR = Join-Path $env:TEMP "genarrative-sccache-local-test"
Remove-Item Env:SCCACHE_OSS_BUCKET -ErrorAction SilentlyContinue
Remove-Item Env:SCCACHE_OSS_ENDPOINT -ErrorAction SilentlyContinue
Remove-Item Env:SCCACHE_OSS_KEY_PREFIX -ErrorAction SilentlyContinue
sccache "C:\Users\DSK\.rustup\toolchains\stable-x86_64-pc-windows-msvc\bin\rustc.exe" -vV
sccache --show-stats
```
如果需要排查 sccache server 状态:
```bash
@@ -44,10 +103,12 @@ sccache --stop-server
sccache --start-server
```
`sccache --stop-server` 本身也可能因为 server 通道已损坏而失败;此时不应阻断本地开发 publish先使用 wrapper 降级完成验证。
`sccache --stop-server` 本身也可能因为 server 通道已损坏而失败;只有确认当前没有 `cargo``rustc``link` 进程后,才用 `taskkill /F /IM sccache.exe /T` 清理残留进程。此时不应阻断本地开发 publish先使用 wrapper 降级完成验证。
## 验证
1. `bash -n scripts/dev-rust-stack.sh`
2. `RUSTC_WRAPPER= CARGO_BUILD_RUSTC_WRAPPER= cargo check --target=wasm32-unknown-unknown`
3. 重新运`npm run dev:rust`,确认 publish 命令带有 `--build-options="--debug"`
2. 冷启动后直接执行 `cargo check -p api-server`,确认不再出现 `Timed out waiting for server startup`
3. `cargo check -p spacetime-module`,确认 proc-macro 依赖和 SpacetimeDB module 都能在 sccache wrapper 下通过。
4. `sccache --show-stats` 显示 `Cache location oss, name: genarrative-sccache`,确认仍在使用 sccache/OSS 缓存。
5. 重新运行 `npm run dev:rust`,确认 publish 命令带有 `--build-options="--debug"`

View File

@@ -2,6 +2,8 @@
日期:`2026-04-27`
状态:历史事故记录。本文针对旧发布包 `start.sh` 的诊断补强,相关 `start.sh` 运行细节已过时,不再作为当前发布或人工排障依据。当前 SpacetimeDB 人工命令不得使用 `--root-dir`CI/CD 脚本内部受控用法除外。
## 1. 问题
执行发布包内 `start.sh` 时,可能只看到:
@@ -16,10 +18,10 @@
## 2. 常见根因
1. `GENARRATIVE_SPACETIME_PORT` 对应端口已被其他进程占用。
2. `.spacetimedb/` root-dir 权限不正确,当前用户无法写入数据、bin 或日志目录。
2. `.spacetimedb/` 运行目录权限不正确,当前用户无法写入数据或日志目录。
3. 目标机 `spacetime` 安装不完整,发布包同步不到可执行的 `bin/current/spacetimedb-cli`
4. 目标机上的 `spacetime` 版本与脚本启动参数不兼容。
5. 旧 SpacetimeDB 进程仍持有同一 root-dir 或数据锁,但当前 `GENARRATIVE_SPACETIME_SERVER_URL` 指向的端口未就绪。
5. 旧 SpacetimeDB 进程仍持有同一运行目录或数据锁,但当前 `GENARRATIVE_SPACETIME_SERVER_URL` 指向的端口未就绪。
6. `.spacetimedb/bin/current/` 下只有 `spacetimedb-cli`,缺少 `spacetimedb-standalone`,日志会显示 `exec failed for .../spacetimedb-standalone`
## 3. 落地修复
@@ -31,11 +33,11 @@
3. 当 SpacetimeDB 进程提前退出或等待超时时,自动打印:
- `GENARRATIVE_SPACETIME_SERVER_URL` 对应的目标地址。
- `GENARRATIVE_SPACETIME_HOST:GENARRATIVE_SPACETIME_PORT` 对应的监听地址。
- 当前 `GENARRATIVE_SPACETIME_ROOT_DIR`
- 当前 `.spacetimedb/` 运行目录
- `logs/spacetimedb.log` 最近 120 行。
- `spacetime server ping` 的原始输出。
- `ss``netstat` 中当前端口的监听情况。
- 同一 root-dir 下仍在运行的 SpacetimeDB 进程。
- 同一运行目录下仍在运行的 SpacetimeDB 进程。
## 4. 现场排查
@@ -43,7 +45,7 @@
```bash
tail -n 120 logs/spacetimedb.log
spacetime --root-dir ./.spacetimedb server ping "${GENARRATIVE_SPACETIME_SERVER_URL:-http://127.0.0.1:3101}"
spacetime server ping "${GENARRATIVE_SPACETIME_SERVER_URL:-http://127.0.0.1:3101}"
ss -ltnp | grep ':3101' || true
```
@@ -54,7 +56,7 @@ exec failed for /var/lib/jenkins/deploy/Genarrative/.spacetimedb/bin/current/spa
No such file or directory (os error 2)
```
说明发布目录的 SpacetimeDB root-dir 中同步了 CLI但没有同步 standalone。现场可先执行
说明发布目录的 SpacetimeDB 运行目录中同步了 CLI但没有同步 standalone。该段仅适用于仍保留 CI/CD 内部受控 `--root-dir` 的旧发布包;新人工排障不要引入 `--root-dir`现场可先执行:
```bash
cd /var/lib/jenkins/deploy/Genarrative

View File

@@ -1,7 +1,9 @@
# start.sh 发布 SpacetimeDB 遇到 403 的处理方案
# SpacetimeDB publish 遇到 403 的处理方案
日期:`2026-04-26`
状态:历史事故记录。本文涉及发布包 `start.sh` 的描述已过时,不再作为当前发布或排障入口。当前人工命令约束以 `AGENTS.md``.hermes/shared-memory/pitfalls.md` 和现行本地/生产技术文档为准;除 CI/CD 脚本内部受控用法外,不再使用 `spacetime --root-dir`
## 1. 问题
执行发布包内 `start.sh` 时,`spacetime publish` 可能在 `Checking for breaking changes...` 后失败:
@@ -23,42 +25,41 @@ SpacetimeDB 的数据库更新权限绑定到创建或被授权的身份。只
3. `GENARRATIVE_SPACETIME_SERVER_URL` 指向其它 SpacetimeDB 服务,而当前 CLI 身份不是该数据库的所有者或授权成员。
4. `.env.local` 中的 `GENARRATIVE_SPACETIME_DATABASE` 指向了另一个环境的数据库名或数据库 identity。
## 3. 落地修复
## 3. 当前处理口径
发布包生成的 `start.sh` 使用发布目录下的 `.spacetimedb/` 作为 SpacetimeDB root
除 CI/CD 脚本内部受控用法外,人工命令、本地联调、临时排障和文档示例不再使用 `spacetime --root-dir`。后续处理遵循
```bash
GENARRATIVE_SPACETIME_ROOT_DIR="${SCRIPT_DIR}/.spacetimedb"
```
1. 本地开发优先使用项目脚本 `npm run dev` / `npm run dev:rust`
2. 手工发布必须显式传 `--server``--server-url`,不依赖 CLI 默认 server。
3. 身份问题通过同一 CLI 登录态、专用运行用户、显式 token 或 SpacetimeDB 侧授权处理。
4. 本地数据隔离使用项目脚本维护的数据目录,必要时通过 `--data-dir` 启动 standalone不要用 `--root-dir` 作为人工排障手段。
启动、探活和发布统一使用:
```bash
spacetime --root-dir="${GENARRATIVE_SPACETIME_ROOT_DIR}" ...
```
`spacetime start` 不再额外设置 `--data-dir`,启动前会先执行 Ubuntu 专用 `sync_ubuntu_spacetime_install`,优先从 `/usr/.local/share/spacetime/bin/<version>/spacetimedb-cli``$HOME/.local/share/spacetime/bin/<version>/spacetimedb-cli` 同步到 `.spacetimedb/bin/current/spacetimedb-cli`;当前线上 `spacetime` 入口为 `/usr/local/bin/spacetime`。启动参数、探活和 root-dir 占用判定都使用同一个 `.spacetimedb/`。这样可以把发布包与部署机全局 `~/.spacetime` 隔离,避免后续人工 `spacetime login` 影响本地发布包。但如果旧 `.spacetimedb/` 已经由另一个身份创建,仍需要按第 4 节处理。
本地 `npm run dev:rust` / `scripts/dev-rust-stack.sh` 也必须遵循同一条规则:`server ping``start``publish` 都显式使用 `server-rs/.spacetimedb/local` 作为 `--root-dir`。不要让发布命令回退到全局 CLI 登录态,否则会出现本地 root 已有目标库权限,但裸 `spacetime publish` 仍使用另一个身份发起预检查并返回 403。
历史上曾用项目级 CLI root 隔离身份该方案已废弃。CI/CD 脚本如因生产运行用户隔离仍保留内部受控用法,不得复制为人工命令模板。
## 4. 排查与处理
先在执行 `start.sh` 的同一台机器、同一用户下确认身份:
```bash
spacetime --root-dir ./.spacetimedb login show
spacetime --root-dir ./.spacetimedb list --server http://127.0.0.1:3101
```
本地开发栈排查时使用仓库本地 root
```bash
spacetime login show
spacetime --root-dir server-rs/.spacetimedb/local login show
spacetime --root-dir server-rs/.spacetimedb/local list --server http://127.0.0.1:3101
spacetime server list
spacetime list --server http://127.0.0.1:3101
```
如果裸 `spacetime login show` 的身份与 `--root-dir server-rs/.spacetimedb/local login show` 不一致,而目标库只出现在本地 root 的 `list` 结果中,说明不能使用裸 `spacetime publish`。应通过 `npm run dev:rust` 或显式追加 `--root-dir=server-rs/.spacetimedb/local` 重新发布。
本地开发栈排查时确认项目脚本记录的实际 server再用同一个 server 验证:
```powershell
Get-Content -Encoding UTF8 server-rs/.spacetimedb/local/data/dev-rust-spacetime-url
spacetime login show
spacetime list --server http://127.0.0.1:3101
```
如果 `spacetime login show` 的身份无权更新目标库,不要尝试通过 `--root-dir` 绕过。应选择以下路径之一:
1. 重新登录目标库 owner 或被授权的身份。
2. 在 SpacetimeDB 侧给当前身份补授权。
3. 如果只是本地开发库且数据可丢弃,按 4.1 重置本地库后重新发布。
4. 如果是连错服务或库名,修正 `.env.local` 中的 `GENARRATIVE_SPACETIME_DATABASE` / `GENARRATIVE_SPACETIME_SERVER_URL`
### 4.1 `npm run dev` 本地 401 / 403 快速恢复
@@ -91,7 +92,7 @@ spacetime login --server-issued-login local
spacetime publish --server local A
```
这条流程适合“本地 `npm run dev` 因旧 token、旧本地库或 CLI 默认 server 混乱导致无法继续”的场景。若当前目标库需要保留数据,不要执行 `spacetime server clear -y`,先按上一段对比 `login show``--root-dir` 和数据库所有者身份。
这条流程适合“本地 `npm run dev` 因旧 token、旧本地库或 CLI 默认 server 混乱导致无法继续”的场景。若当前目标库需要保留数据,不要执行 `spacetime server clear -y`,先确认 `login show`目标 server、数据库名和数据库所有者身份。
如果目标是本地部署库,且允许清空本地数据:
@@ -105,7 +106,7 @@ mv .spacetimedb ".spacetimedb.backup.$(date +%Y%m%d-%H%M%S)"
1. 不要删除 `.spacetimedb/`
2. 找到创建该数据库的 SpacetimeDB 身份。
3. 用该身份对应的 CLI root 执行发布,或在 SpacetimeDB 侧补授权后再发布。
3. 用该身份登录当前 CLI,或在 SpacetimeDB 侧补授权后再发布。
如果目标是其它 SpacetimeDB 服务:
@@ -116,5 +117,6 @@ mv .spacetimedb ".spacetimedb.backup.$(date +%Y%m%d-%H%M%S)"
## 5. 约束
1. `--clear-database` 只处理 schema 冲突时的数据清理,不会绕过 SpacetimeDB 身份授权。
2. 不要通过切回旧 `server-node` 或 PostgreSQL 绕过发布错误
3. 前端与 `api-server` 的数据库名必须和 `start.sh` 发布的库名一致,否则后续接口会连到未发布或无权限的库。
2. 除 CI/CD 脚本内部受控用法外,不要在人工排障或文档示例中使用 `spacetime --root-dir`
3. 不要通过切回旧 `server-node` 或 PostgreSQL 绕过发布错误。
4. 前端与 `api-server` 的数据库名必须和 `start.sh` 发布的库名一致,否则后续接口会连到未发布或无权限的库。

View File

@@ -2,6 +2,8 @@
日期:`2026-04-27`
状态:历史事故记录。本文只解释旧发布包 `start.sh` 的一次误报修复,相关 `root-dir` 检测不再作为当前发布或人工排障口径。当前人工命令不得使用 `spacetime --root-dir`CI/CD 脚本内部受控用法除外。
## 1. 问题
执行发布包内 `start.sh` 时,可能出现: