From b2820ec024c9f4e331ef4e8797310c4113e3bc37 Mon Sep 17 00:00:00 2001 From: starmen1265 Date: Thu, 16 Jul 2026 19:19:59 +0800 Subject: [PATCH] =?UTF-8?q?docs(workflow):=20=E5=BB=BA=E7=AB=8B=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E7=AE=A1=E7=90=86=E4=B8=89=E6=AE=B5=E5=BC=8F=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E4=B8=8E=E7=BB=8F=E9=AA=8C=E7=9F=A5=E8=AF=86?= =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 problem-solving skill:固化「问题分析→工作记录→知识沉淀」9步流程与3模板 - 新建 docs/knowledge/ 经验知识库(README/INDEX/临时方案登记/坑-UE5引擎含2条迁移示例) - GIT-GUIDE 补 §2.7 临时代码 [TEMP-INVESTIGATE] 约定、§2.8 fix 提交引用 issue - CLAUDE.md 项目管理段加问题管理引用 - 配套 Gitea 标签 type:bug / type:investigation(后台已建) --- .claude/skills/problem-solving/SKILL.md | 134 ++++++++++++++++++++++++ CLAUDE.md | 1 + docs/common/GIT-GUIDE.md | 22 ++++ docs/knowledge/INDEX.md | 23 ++++ docs/knowledge/README.md | 52 +++++++++ docs/knowledge/临时方案登记.md | 21 ++++ docs/knowledge/坑-UE5引擎.md | 28 +++++ 7 files changed, 281 insertions(+) create mode 100644 .claude/skills/problem-solving/SKILL.md create mode 100644 docs/knowledge/INDEX.md create mode 100644 docs/knowledge/README.md create mode 100644 docs/knowledge/临时方案登记.md create mode 100644 docs/knowledge/坑-UE5引擎.md diff --git a/.claude/skills/problem-solving/SKILL.md b/.claude/skills/problem-solving/SKILL.md new file mode 100644 index 0000000..581ebe6 --- /dev/null +++ b/.claude/skills/problem-solving/SKILL.md @@ -0,0 +1,134 @@ +--- +name: "problem-solving" +description: "问题解决技能 — 改 bug / 排查复杂问题时,按「问题分析 → 工作记录 → 知识沉淀」三段式产出。当需要「修 bug」「排查问题」「调查原因」「问题分析」「写工作记录」「沉淀知识库」时使用。" +--- + +# 问题解决(Problem Solving) + +> 改 bug / 做复杂改动时,按「问题分析 → 工作记录 → 知识沉淀」三段式产出。 +> **核心范式**:Gitea issue 是工作台(承载问题分析 + 工作记录,事务性);`docs/knowledge/` 是精选集(只收值得长期保留的坑);临时代码验证完即删。 + +## 触发条件 + +- 用户要求**修 bug、排查问题、调查根因**,且问题非一行 typo 类简单修改 +- 用户说「修 bug」「排查」「为什么…」「调查」「这个问题怎么回事」等 +- 改动涉及多个文件 / 需要先理解现状才能动手的复杂改动 + +**不触发**(直接改 + 普通 `fix(scope)` 提交):明显的单行修复、typo、数值微调。 + +--- + +## 九步流程 + +### 1. 判断复杂度 + +简单修复(单行、明显错误)→ 直接改 + `fix(scope)` 提交,**不走本流程**。 +复杂问题(需调查、跨文件、根因不明)→ 继续后续步骤。 + +### 2. 开 / 关联 Gitea issue + +调用 `gitea-pm` / `gitea-collab` skill: +- 没有对应 issue → 开一个,打标签 `type:bug`(缺陷修复)或 `type:investigation`(纯调查)+ `status:in-progress` +- 已有 issue → 关联,更新为 `status:in-progress` + +> 每个「要解决的问题」都应有对应 issue——问题分析和工作记录都挂在它上面。 + +### 3. 问题分析(写入 issue 描述 / 首条评论) + +按「问题分析模板」填写:现象 / 复现 / 影响范围 / 假设与验证 / 初步结论。这是调查过程的留痕。 + +### 4. 本地调查 + +写临时验证代码验证假设(文件名前缀 `tmp_` / `dev_`,文件头 `// [TEMP-INVESTIGATE: issue#XX] 验证后删除`)。**关键验证代码片段**以代码块形式记入 issue「假设与验证」章节。 + +### 5. 清理临时代码 + +验证完**即删**——删除 `tmp_`/`dev_` 文件、`git revert` 或删除 `[TEMP-INVESTIGATE]` 的 commit。最后 `grep -r "TEMP-INVESTIGATE" Source/ tools/` 确认无残留。 + +> 原则:删除的是可运行 artifact,保留的是 insight(结论 + 片段已写入 issue)。 + +### 6. 修复 + +写正式代码 / 蓝图,遵循 `code-implementation` skill 规范 + Git 规范(`fix(scope)`,C++ 与蓝图分开提交,见 `docs/common/GIT-GUIDE.md`)。 + +### 7. 工作记录(写入 issue 关闭总结评论) + +按「修复总结模板」发一条评论:问题 / 根因 / 解决方案 / 验证 / 影响范围 / 是否沉淀知识库。 + +> **与 deviation-report 的分工**:问题涉及「实现 vs 执行案偏差」时(有执行案对照)→ 用 `deviation-report` skill 写偏差报告;纯 bug 修复(无执行案对照)→ 用本「修复总结」。两者互补。 + +### 8. 知识库评估 + +判断这个坑是否值得长期保留(**任一为是**即提炼): +- 会复发吗?(换人/换系统会再踩) +- 根因非显而易见吗?(光看代码看不出来) +- 当前是临时方案吗? + +**是** → 提炼一条进 `docs/knowledge/` 对应主题文件(`坑-<主题>.md`),更新 `docs/knowledge/INDEX.md`;若是临时方案,再登记到 `docs/knowledge/临时方案登记.md`。 +**否** → issue 关闭即可,不必沉淀。 + +> 动手前先读 `docs/knowledge/INDEX.md`,看有没有相关坑可避让。 + +### 9. 关闭 issue + +更新 issue 为 `status:done`,在评论里记录产出位置(分析评论 / 修复总结评论 / 知识库条目路径)。 + +--- + +## 模板 + +### 问题分析模板(issue 描述 / 首条评论) + +```markdown +## 问题现象 +## 复现步骤 +## 影响范围 +## 假设与验证(调查过程) +- 假设1:… → 验证手段:… → 结论:… +- 假设2:… +## 初步结论 / 根因 +## 关键验证代码片段(临时代码已删,仅留片段) +``` + +### 修复总结模板(issue 关闭总结评论) + +```markdown +## 修复总结 +### 问题(一句话) +### 根因 +### 解决方案(改了哪些 文件/蓝图/C++,分条) +### 验证(怎么确认修好) +### 影响范围(是否波及其他系统) +### 是否沉淀知识库?(是→已提炼到 docs/knowledge/xxx;否→为何不必) +``` + +### 知识条目模板(`docs/knowledge/坑-<主题>.md`) + +```markdown +### [K-XXX] 标题 +- 来源: Gitea issue #XX +- 症状: … +- 根因: … +- 避坑做法: …(核心价值) +- 状态: ✅正式方案 / ⚠️临时方案(预计转正时机:…) +- 关联: [[系统-技术方案]]、相关代码位置 file:line +``` + +ID 全库统一递增(K-001、K-002…),不分主题。新增后同步更新 `INDEX.md`。详见 `docs/knowledge/README.md`。 + +--- + +## 产出物清单(每次复杂问题必须交付) + +1. ✅ issue 问题分析(描述 / 首条评论) +2. ✅ issue 关闭总结评论(修复总结) +3. ⚙️〔条件〕`docs/knowledge/` 知识条目 + `INDEX.md` 更新(仅当值得沉淀) +4. ✅ 临时代码已清理(`grep TEMP-INVESTIGATE` 无残留) + +--- + +## 核心原则 + +- **issue 是工作台,知识库是精选集**:别把过程流水账灌进 docs,只提炼有长期价值的。 +- **临时代码验证完即删**:仓库只留正式实现,结论和片段留在 issue。 +- **诚实记录根因**:工作记录的价值在于「为什么」,不在于「我改了什么」——后者看 commit 就知道。 diff --git a/CLAUDE.md b/CLAUDE.md index 6677683..9aa2f1d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,6 +19,7 @@ - **工具**: Gitea(Issues + Milestones) - **进度查询**: Pipeline Tracker(Meta Issue,仅记录当前阶段和阶段历史) - **配置文件**: `.claude/skills/gitea-pm/gitea-config.json`(含连接信息、Token、角色映射、标签定义) +- **问题管理**: 改 bug / 排查复杂问题走 `problem-solving` skill(问题分析 + 工作记录挂 Gitea issue,经验沉淀进 `docs/knowledge/`);详见 [`docs/knowledge/README.md`](docs/knowledge/README.md) --- diff --git a/docs/common/GIT-GUIDE.md b/docs/common/GIT-GUIDE.md index 0c93dd2..de8509b 100644 --- a/docs/common/GIT-GUIDE.md +++ b/docs/common/GIT-GUIDE.md @@ -164,6 +164,28 @@ git commit -m "refactor(inventory): 拆分背包数据层与UI层" - `Binaries/`、`Intermediate/`、`Saved/`、`DerivedDataCache/` - `.vs/`、`*.sln`(由引擎自动生成) +### 2.7 临时代码与调查脚本(验证完即删) + +排查问题时往往需要写临时验证代码、测试脚本、一次性工具。约定如下(详见 `problem-solving` skill): + +- **默认不进仓库**:临时代码只在本地 / 临时分支跑,验证完删除。 +- **若必须 commit**(如要在 UE5 里跑):用 `wip` 类型,message 标注 `[TEMP-INVESTIGATE: issue#XX]`,验证后 `git revert` 或删除该 commit。 +- **文件标记**:文件名前缀 `tmp_` / `dev_`,文件头注释 `// [TEMP-INVESTIGATE: issue#XX] 验证后删除`。 +- **清理检查**:关闭 issue 前执行 `grep -r "TEMP-INVESTIGATE" Source/ tools/`,确认无残留。 +- **保留什么**:结论 + 关键代码片段以代码块形式写入 issue 评论,**不保留可运行文件**。 + +> 原则:删除的是 artifact,保留的是 insight。 + +### 2.8 fix 提交引用 issue + +Bug 修复 / 问题排查类提交,在 body 里引用对应 Gitea issue 号,便于溯源: + +```bash +git commit -m "fix(camera): 修复穿墙时摄像机卡顿问题 + +issue #42" +``` + --- ## 三、版本号规范 diff --git a/docs/knowledge/INDEX.md b/docs/knowledge/INDEX.md new file mode 100644 index 0000000..8a62191 --- /dev/null +++ b/docs/knowledge/INDEX.md @@ -0,0 +1,23 @@ +# 知识库索引 + +> 所有经验知识条目一览。**动手改东西前先扫这里。** +> 最后更新:2026-07-16 + +## 主题文件 + +| 文件 | 条目数 | 说明 | +|------|--------|------| +| [坑-UE5引擎.md](坑-UE5引擎.md) | 2 | UE5 引擎相关:生命周期、初始化时序、API 陷阱 | + +## 全部条目 + +### 坑-UE5引擎 + +| ID | 标题 | 状态 | 一句话 | +|----|------|------|--------| +| K-001 | Actor BeginPlay 时序竞争 | ✅正式 | 子系统 Driver 可能晚于 Character 初始化,依赖项要懒创建 | +| K-002 | Component Timer/Widget 必须 EndPlay 清理 | ✅正式 | 防 Respawn 野指针崩溃 | + +## 临时方案(技术债) + +详见 [临时方案登记.md](临时方案登记.md)。当前待转正:**0 项**。 diff --git a/docs/knowledge/README.md b/docs/knowledge/README.md new file mode 100644 index 0000000..eb0444b --- /dev/null +++ b/docs/knowledge/README.md @@ -0,0 +1,52 @@ +# 经验知识库 + +> ChildHood 项目的「经验知识库」——记录踩过的坑、根因、避坑做法、临时方案。 +> 与 `docs/` 其他目录的区别:`design/`/`technical/`/`art/` 是**设计知识**(要做什么、怎么设计),本库是**经验知识**(踩过什么坑、怎么避开)。 + +## 这是什么 + +每次修 bug 或做复杂改动时,**问题分析和修复记录挂在 Gitea issue 上**(事务性,随 issue 归档)。但有些坑值得长期保留——关闭的 issue 不会再被翻,同类坑会反复踩。**本库就是这些长期经验的精选集**。 + +只有「会复发的、非显而易见的、值得未来的自己或别人避让的」才进本库。一次性事务不必沉淀。 + +## 目录结构 + +| 文件 | 用途 | +|------|------| +| `INDEX.md` | 总索引——所有条目一览,AI/人快速扫描的入口 | +| `临时方案登记.md` | 技术债看板——所有「临时方案」集中登记,每条带「何时转正」 | +| `坑-<主题>.md` | 按主题归集的坑(`坑-UE5引擎` / `坑-性能` / `坑-美术资产` / `坑-配置`…) | + +## 何时写一条知识条目 + +修复一个问题后,问自己(`problem-solving` skill 会自动问): + +- 这个坑**会复发**吗?(换个人、换个系统会不会再踩) +- 根因**非显而易见**吗?(光看代码看不出来) +- 当前是**临时方案**吗?(需要标记未来转正) + +**任一为是** → 提炼一条进对应主题文件 + 更新 `INDEX.md`。 + +## 怎么写(条目模板) + +``` +### [K-XXX] 标题 +- 来源: Gitea issue #XX(或 偏差报告 / 审查记录) +- 症状: 现象是什么 +- 根因: 为什么会这样 +- 避坑做法: 应该怎么做(这是条目的核心价值) +- 状态: ✅正式方案 / ⚠️临时方案(预计转正时机:…) +- 关联: [[系统-技术方案]]、相关代码位置 file:line +``` + +- ID 用 `K-001`、`K-002` 递增(全库统一编号,不分主题)。 +- **临时方案**条目同时登记到 `临时方案登记.md`。 + +## 怎么检索 + +- **人**:看 `INDEX.md` 一览,或直接翻主题文件。 +- **AI**:动手改某系统前,先读 `INDEX.md` 判断有没有相关坑。`problem-solving` skill 会自动做这步。 + +## 新增主题文件 + +坑多了就开新主题文件(如 `坑-性能.md`),命名 `坑-<主题>.md`,并在 `INDEX.md` 的「主题文件」表里登记。 diff --git a/docs/knowledge/临时方案登记.md b/docs/knowledge/临时方案登记.md new file mode 100644 index 0000000..80af03b --- /dev/null +++ b/docs/knowledge/临时方案登记.md @@ -0,0 +1,21 @@ +# 临时方案登记(技术债看板) + +> 所有「临时方案」集中登记。每条都要写清:**临时在哪、为什么临时、何时/什么条件下转正**。 +> 定期 review,转正后从这里移除(或标记 ✅已转正留作历史),并同步对应知识库主题文件里的条目状态为 ✅正式方案。 + +## 登记表 + +| ID | 临时方案 | 位置 | 为什么临时 | 转正条件/时机 | 登记日期 | 状态 | +|----|----------|------|------------|----------------|----------|------| +| _(暂无)_ | | | | | | | + +## 条目格式(登记时复制) + +``` +| K-XXX | <一句话描述临时方案> | file:line / 蓝图路径 | <为什么现在只能临时> | <何时/什么条件下转正> | YYYY-MM-DD | ⚠️待转正 | +``` + +转正流程: +1. 把正式实现做掉。 +2. 在对应主题文件(如 `坑-UE5引擎.md`)的知识条目里,状态改为 `✅正式方案`。 +3. 回到本表,把该行状态改为 `✅已转正`(保留一行作为历史),或直接删除。 diff --git a/docs/knowledge/坑-UE5引擎.md b/docs/knowledge/坑-UE5引擎.md new file mode 100644 index 0000000..eaeaee8 --- /dev/null +++ b/docs/knowledge/坑-UE5引擎.md @@ -0,0 +1,28 @@ +# 坑-UE5引擎 + +> UE5 引擎相关的坑:Actor/Component 生命周期、初始化时序、引擎 API 陷阱等。 +> 条目按 ID 排列。新增条目时同步更新 [INDEX.md](INDEX.md)。 + +--- + +### [K-001] Actor BeginPlay 时序竞争:子系统 Driver 可能晚于 Character 初始化 + +- **来源**: P-013 实现偏差报告 · 偏差3 +- **症状**: 在 `AChildHoodCharacter::BeginPlay` 中通过 `ASystemDriver::Get` 取 Driver,再读子系统(如收集系统)的进度数据时,可能读到未初始化的值(Progress=0、CollectedIDs 空),导致进度 Widget 显示错误或存档恢复失败。 +- **根因**: UE5 **不保证不同 Actor 的 BeginPlay 执行顺序**。Character 可能先于 `ASystemDriver` 完成 BeginPlay——此时 Driver 虽然存在,但其持有的子系统尚未执行 `RestoreFromPersistence`。 +- **避坑做法**: 不要在 `BeginPlay` / `Initialize` 里立即创建依赖其他子系统的对象、或读取其状态。改为**首次有效 Tick 时懒创建**——等到 World 完全就绪、依赖子系统完成初始化后再创建/读取。 +- **状态**: ✅正式方案(已用于 `UCollectionHUDComponent` 的进度 Widget 创建) +- **关联**: `docs/technical/收集系统-技术方案.md` §6、`Source/.../CollectionHUDComponent.cpp` + +--- + +### [K-002] Component 持有的 Timer / Widget 必须在 EndPlay 清理,防 Respawn 野指针 + +- **来源**: P-013 实现偏差报告 · 审查修复2 +- **症状**: 角色 Respawn(销毁旧 Character、重建新 Character)时崩溃——旧 Component 上还挂着 `SetTimer` 注册的回调,触发时访问已销毁的 UMG Widget,野指针。 +- **根因**: Component 被销毁时,UE 不会自动清理你手动注册的 `FTimerHandle`,也不会自动移除 `AddToViewport` 的 Widget。这些引用悬挂,下次 Tick 或 Timer 触发即崩。 +- **避坑做法**: 凡是 Component 持有 `FTimerHandle`(`SetTimer` 注册过)或 `AddToViewport` 的 UMG Widget,**必须 override `EndPlay`**,在里头: + - `GetWorld()->GetTimerManager().ClearTimer(MyTimerHandle);`(清所有相关句柄) + - `if (MyWidget) MyWidget->RemoveFromParent();`(Widget 还有效则移除) +- **状态**: ✅正式方案(项目所有 Character 持有 Component 的卫生写法,保持一致) +- **关联**: `Source/.../CollectionHUDComponent.cpp` EndPlay