新建业务或平台模块时,项目目录本身不构成治理声明——目录不会告诉编译器自己依赖谁、对外暴露什么、拥有哪些权限。模块必须在 owner 目录中声明编译期治理事实:模块标识、允许的依赖、公开契约由源生成器从 owner-local 的类型化标记投影而来,权限与 Features 则登记在各自的 catalog 特性里。运行时绝不扫描 assembly 或读取属性。
AppModule 类型化标记
V2 治理标记位于 BitzOrcas.Modularity.Governance.AppModuleAttribute,标注在 owner 项目里的一个模块标记类型上(惯例文件名 XxxModule.cs)。构造参数只有模块显示名;其余身份以 init 属性补齐:
Code——稳定模块代码(如tracker),用于权限码前缀{code}.{resource}.{action}与 catalog 索引,缺省时取Name的 kebab-case 形式;BaseNamespace——模块基础命名空间,缺省时由生成器从标注类型所在程序集推导;PublicContractNamespaces——仅这些命名空间可被其他模块引用,缺省为BaseNamespace + ".Contracts"。
一个类型只能标注一次,且与旧版 [assembly: AppModule] 的根本区别在于:声明位置从程序集级收敛到 owner-local 类型,让依赖关系与权限归属在同一处可审计,并彻底剥离了 DI 行为耦合。
以下是框架仓库中真实存在的 Tracker 模块标记原文(src/Platform/Tracker/BitzOrcas.Platform.Tracker.Contracts/TrackerModule.cs):
namespace BitzOrcas.Platform.Tracker.Contracts;
using BitzOrcas.Modularity.Governance;
/// <summary>/// 事项跟踪模块治理标记/// </summary>[AppModule("Tracker", Code = "tracker", BaseNamespace = "BitzOrcas.Platform.Tracker")]// 每条 DependsOn 都是一条显式声明的运行时依赖边。// 声明七条治理边意味着 Tracker 的能力横跨鉴权、发布跟踪、附件、检索、通知与菜单。[DependsOn("Authorization")][DependsOn("ReleaseManagement")][DependsOn("Files")][DependsOn("Search")][DependsOn("Notifications")][DependsOn("Menu")][DependsOn("Identity")]internal sealed class TrackerModule;DependsOn 是显式的,不会从观测到的 ProjectReference 自动扩展——删掉一条声明就是真断开,评审 diff 因此具有含义。需要完整图的 Host 声明 [assembly: GenerateModuleGovernanceCatalog];生成器在编译期聚合被引用 assembly 中的公开 IModuleContributionProvider 索引并生成 ModuleGovernance.Generated.cs。不存在 AppDomain.GetAssemblies、Assembly.GetTypes 或 DI Service Locator。
当前治理口径
源码当前有 36 个 [AppModule] 类型化标记。PlatformModuleGovernanceLocalizationTests.ExpectedOwnerModules 显式列出 27 个 owner-local 基线:原 26 个收敛模块加上 LicenseManagement。其余九个标记分成三组:
- foundation / connector:
Platform、IndustryExtensions、LegalCalculators、LegalConnectors、ToolConnectors; - 新增产品 owner:
Announcements、CommercialDistribution、ReleaseManagement; - Golden Use Case:
src/Modules/Sandbox中的Sandbox。
生成目录覆盖测试不会只信这份 27 项字典。它动态发现 src/Platform 与 src/Modules 的全部 typed marker,再与 API Host 编译生成的 GeneratedModuleGovernanceCatalog 做有序、唯一比较。因此上述 36 个标记都必须进入生成目录。
文档也有 36 份模块手册,但采用面向开发者的能力口径,不与 typed marker 一一对应:手册加入 Framework 横切能力 Auditing、Multitenancy,不把 foundation Platform 和 Golden Use Case Sandbox 当作生产业务模块手册。两个总数碰巧相同,评审时仍要区分”治理标记”与”开发手册”。
中央 foundation 边界
src/Platform/BitzOrcas.Platform.Application/PlatformModuleGovernance.cs 当前只有 27 行,只保留 LegalConnectors 与 ToolConnectors 的 legacy assembly 声明,用来提供尚未迁入 owner-local catalog 的 OwnedPermissions / OwnedFeatures。两者已经各自拥有 V2 typed marker;补齐权限与 Feature catalog 后,这两条 legacy 声明即可删除。
Platform、IndustryExtensions 与 LegalCalculators 已改为同项目内独立 typed marker,不再由中央 assembly 声明承担。业务模块不得回填中央文件,且门禁要求它保持 ≤ 50 行。新增平台模块应在 owner 项目中加入标记和必需 catalogs,把治理生成器作为 analyzer 引用,并让目标 Host 正常引用模块 assembly;不要维护 Host 模块名列表。
遗留账本棘轮
通用模块接入仍由 ModuleGovernanceRegistrationTests 与 0001-module-governance-legacy-ledger.json 守卫。账本是一个只能收缩的棘轮;maxLegacyRoots 必须随遗留根删除而减小(当前为零)。一个无编译期注册的新模块根会测试失败;历史遗留 assembly manifest 仅出现在带 owner 与删除条件的兼容性账本中。
新模块评审顺序
- 确认目录是真正的 owner,而不是为了复用代码建立的浅模块。
- 检查
AppModule名称、Code、BaseNamespace 和DependsOn是否稳定且无循环。 - 权限、Feature、发布事件和订阅事件分别进入 owner-local catalog。
- Host 通过项目引用让生成器发现模块,不添加反射扫描或字符串注册。
- 运行 localization、registration、generated-catalog 与 readiness matrix 测试。
- 新能力需要模块手册时同步目录、示例和源码验证;不要用手册页替代治理 marker。
源码复核
评审记录应同时写明 typed marker 数、显式 owner 基线数与手册数,避免下一次只更新其中一个口径。
# 统计 typed marker,并核对显式 owner baseline 与动态 catalog coverage。rg -n '\[AppModule\(' src/Platform src/Modules -g '*.cs'rg -n "ExpectedOwnerModules|DiscoverTypedModuleNames|GeneratedModuleGovernanceCatalog" \ tests/BitzOrcas.Architecture.Tests/PlatformModuleGovernanceLocalizationTests.cs
# 中央 legacy 文件必须保持薄,并且 ledger 只能收缩。wc -l src/Platform/BitzOrcas.Platform.Application/PlatformModuleGovernance.cscat docs/architecture/00-governance/manifests/0001-module-governance-legacy-ledger.json