mcpField
C
consolidate-concepts

consolidate-concepts

github.com/plainlang开发8045 次安装今天更新
代码仓库

关于 consolidate-concepts

用于将多个 `.plain` 模块中的共享概念集中到一个导入模块的技能。它指导分析、规划和结构调整,要求先获明确批准,并保持功能、实现和测试要求不变。

主要功能

  1. 01梳理概念及其依赖
  2. 02规划共享导入模块
  3. 03更新导入与导出声明
  4. 04保持行为和各项要求不变
  5. 05验证引用及文件结构

适用场景

  1. 01消除模块间重复的概念定义
  2. 02简化冗长的导出概念列表
  3. 03模块拆分后共享领域定义

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/plainlang/plain-forge --skill consolidate-concepts

安装后在 Claude Code 中输入/consolidate-concepts确认已加载。

详细介绍

整合概念

请先加载规则。 在读取、编辑或编写任何 .plain 文件之前,调用 load-plain-reference 技能,并阅读它指引你查看的规则文件。只有在本次对话中已运行过 load-plain-reference 时,才可跳过此步骤。

使用时机

  • 多个模块分别定义了相同或密切相关的概念。
  • requires 链使用冗长的 exported_concepts 列表来共享定义,而改用导入会更简单。
  • 执行 refactor-module 拆分后,共享概念出现重复或导出方式不够合理。
  • 用户希望为多个模块使用的领域概念建立单一事实来源。

指导原则

这是一次结构性重构。所有受影响模块的行为必须保持不变。不得更改任何功能规格、实现要求或测试要求。只移动概念定义——从分散的位置移至一个共享导入模块,并更新各模块的 import 列表以引用该模块。

输入

需要整合概念的模块集合,以及可选的新(或现有)导入模块名称。如果未指定,请询问用户。

阶段 1 — 分析各模块中的概念

  1. 读取所有源模块。 对涉及的每个 .plain 文件,读取完整文件,包括 frontmatter、定义、实现要求、测试要求和功能规格。同时读取其 import 和 requires 链。
  2. 建立概念清单。 对所有源模块中定义的每个概念,记录:
    • 定义位置(文件及行号)
    • 哪些模块引用了它(在定义、功能规格、实现要求或测试要求中)
    • 它当前是否位于 exported_concepts 列表中
    • 它的定义引用了哪些其他概念(依赖关系图)
  3. 确定整合候选项。 满足以下任一条件的概念应予以整合:
    • 在一个模块中定义,却被另一个模块中的规格引用(目前通过 exported_concepts 共享)
    • 在多个模块中重复定义
    • 属于基础领域概念,逻辑上应纳入共享词汇表
  4. 确定应保留在本地的概念。 满足以下任一条件的概念应保留在其所属模块中:
    • 仅用于该模块自身的规格和定义
    • 属于内部实现细节,在模块外没有意义

阶段 2 — 制定整合计划

向用户说明计划,并在进行更改前获得明确确认。

2a. 选择目标导入模块
  • 新建导入模块 — 在 template/ 中创建新的 .plain 文件。选择一个能体现共享领域的名称(例如 template/myapp-concepts.plain)。
  • 现有导入模块 — 将概念添加到受影响模块已使用的导入模块中。这样可避免增加另一个导入引用。

如果目标是现有导入模块,请完整读取该文件,了解其中已有的内容。

2b. 确定要移动的概念

对于每个整合候选项,确认:

  • 将从其当前模块的 ***definitions*** 部分移除该概念。
  • 将该概念添加到目标导入模块的 ***definitions*** 部分。
  • 将概念的完整定义文本(包括属性和约束的所有子弹项)原样移动。
2c. 确定目标中的概念顺序

导入模块中的概念必须按顺序排列,以确保每个概念都在其引用的所有概念之后定义。使用阶段 1 中的依赖关系图,确定有效的拓扑顺序。

2d. 确定导入和导出变更

对于每个受影响的模块,确定其 frontmatter 变更:

变更适用情况
将新导入添加到 import 列表模块尚未导入目标项
从 exported_concepts 中移除概念这些概念仅为了共享定义而导出——现在由导入处理
在 exported_concepts 中保留概念下游模块仍需通过导出获取这些概念(因为这些下游模块不会导入新模板)

重要: import 会向导入该项的模块提供定义。requires 模块中的 exported_concepts 会在构建链中向下游模块提供概念。如果下游模块现在会直接 import 共享模板,就可以从 exported_concepts 中移除该概念。如果下游模块不导入该模板,则必须继续导出该概念。

2e. 提出计划

向用户总结:

  • 目标导入模块(新建或现有)及其路径
  • 要移动的概念列表,以及每个概念的来源模块
  • 保留在本地的概念列表(以及原因)
  • 各模块的 frontmatter 变更(新增 import 项、从 exported_concepts 中移除的项目)
  • 确认不会更改任何功能规范、实现要求或测试要求

继续之前,必须获得用户的明确确认。

阶段 3 — 执行

3a. 创建或更新导入模块

如果要创建新的导入模块:

  1. 创建带有 YAML frontmatter 的 template/<name>.plain。如果它需要来自另一个导入项的概念,则将该项添加到自己的 import 列表中。
  2. 添加一个 ***definitions*** 部分,按依赖顺序列出所有合并后的概念。
  3. 不要添加 ***functional specs*** —— 导入模块不得包含功能规范。

如果要更新现有导入模块:

  1. 读取当前文件。
  2. 将新概念插入 ***definitions*** 部分,并按照相对于现有概念的依赖顺序排列。
  3. 确认没有与文件中已有概念或其自身导入项中的概念重名。
3b. 更新每个源模块

对于移出了概念的每个模块:

  1. 移除概念定义:从模块的 ***definitions*** 部分移除概念定义,包括所有子项。
  2. 添加导入:将该导入项添加到模块 YAML frontmatter 的 import 列表中(如果尚未添加)。
  3. 更新 exported_concepts:移除不再需要导出的概念(参见 2d)。
  4. 不要修改 ***functional specs***、***implementation reqs*** 或 ***test reqs*** —— 这些部分中的概念引用(:ConceptName:)保持不变,因为现在由导入提供该概念。
3c. 更新下游模块(如适用)

如果某个概念已从模块的 exported_concepts 中移除,而下游模块依赖该概念:

  1. 将新的导入项添加到下游模块的 import 列表中,使其直接获取这些概念。
  2. 确认下游模块的规范仍可解析所有概念引用。

阶段 4 — 验证

4a. 概念可用性检查

对于每个受影响的模块(源模块、下游模块和导入模块本身):

  • 功能规范中引用的每个 :Concept: 都可解析(在本地定义、通过导入获取,或通过 requires 导出的概念获取)
  • 定义中引用的每个 :Concept: 都在引用它的概念之前定义
  • 实现要求和测试要求中引用的每个 :Concept: 都可解析
4b. 重复项检查
  • 同一概念未同时定义在导入模块和源模块中
  • 同一概念未同时定义在导入模块和源模块使用的另一个导入项中
  • 在每个模块的完整解析范围(本地 + 导入 + requires 导出项)内,概念名称全局唯一
4c. 定义完整性检查
  • 每个迁移概念的定义文本都与原文完全一致——没有改写,也没有遗漏子条目
  • 导入模块中的概念顺序符合依赖关系图(没有前向引用)
4d. 无行为变更检查
  • 未修改任何模块中的 ***functional specs***
  • 未修改任何模块中的 ***implementation reqs***
  • 未修改任何模块中的 ***test reqs***
  • 未修改任何测试 plain 文件
4e. 结构验证

对于导入模块:

  • 文件位于 template/ 目录中
  • 不包含 ***functional specs***
  • 不使用 requires
  • YAML frontmatter 格式正确

对于每个源模块:

  • YAML frontmatter 的 import 列表包含目标导入模块
  • exported_concepts 正确(没有过度导出,也没有遗漏导出)
  • 模块仍至少包含一条功能规格和一条实现要求
4f. 阅读所有已修改文件

完整阅读每个已修改的 .plain 文件,并将更改提交给用户审批。如果用户要求修改,请进行修改并重新验证。

常见陷阱

移动仅在本地使用的概念

如果某个概念仅在单个模块内被引用,将其整合到共享导入中会造成不必要的耦合。请保留在本地。

忘记更新下游模块

从 exported_concepts 中移除某个概念后,任何 requires 源模块且引用了该概念的模块都会出错——除非它们现在导入了共享模板。务必追踪完整的依赖链。

破坏概念顺序

导入模块中的概念必须按拓扑顺序排列。如果 :Meal: 在定义中引用了 :MealType:,那么 :MealType: 必须先出现。源模块中的局部顺序可能原本正确,但合并不同模块中的概念时,需要重新建立有效的顺序。

创建循环导入

导入模块不能 import 一个直接或间接反向导入它的模块。如果共享概念引用了现有模板中的概念,则新导入模块应导入该模板,而不是反过来。

过早从 exported_concepts 中移除概念

只有在所有需要该概念的下游模块现在都能通过 import 获取它时,才从 exported_concepts 中移除该概念。如果哪怕有一个下游模块没有导入共享模板,就必须保留该导出。

验证清单

  • 用户在执行前确认了整合计划
  • 所有迁移概念都在导入模块中定义,且文本完全一致
  • 导入模块中的概念顺序符合依赖关系
  • 导入模块和源模块中没有重复定义的概念
  • 每个受影响模块的 import 列表都包含目标导入模块
  • exported_concepts 已正确更新——没有遗漏导出,也没有不必要的导出
  • 所有受影响模块中的概念引用都能正确解析
  • 未修改任何功能规格、实现要求、测试要求或测试 plain 文件
  • 导入模块位于 template/ 中,且没有功能规格或 requires
  • 没有引入循环导入
  • 必要时已更新下游模块
  • 用户已批准最终结果

评论

支持 Markdown