Skip to content
bitzorcas
中EN

Reference

Industry Extensions 打包、治理与运行时边界

深入解释三个可选计算程序集、依赖图、寄宿治理 marker、API Host 未引用事实、LegalCalculators 反向消费、集成 wrapper 以及权限、租户、隐私和审计责任。

Last updated

Industry Extensions 的隔离单位是程序集,不是运行时模块实例。三个 csproj 都只引用 Domain(Auction 再引用 Finance),没有 Application/Contracts/Infrastructure 分层,也没有服务注册入口。

1. 物理项目

项目Description 声明真实内容
Finance显式选择的金融计算器5 个计算器 + 1 个分档引擎 + Error catalog
HR显式选择的 HR 计算器LeaveCalculator + LeavePolicySchedule + Error catalog
Auction显式选择的拍卖计算器AuctionCommissionCalculator + Error catalog

所有项目 TargetFramework 为 net10.0,开启 Nullable/ImplicitUsings,没有 PackageId、Version、SourceLink 或 NuGet pack 元数据。所谓“可选包”当前主要指 ProjectReference 选择,不是已经独立发布和签名的商业 NuGet 产品。

2. 依赖方向

声明模块身份不引用

Framework Domain

IndustryExtensions.Finance

IndustryExtensions.Hr

IndustryExtensions.Auction

LegalCalculators

Platform.Application
治理 marker

BitzOrcas.Api

旧边界“通用平台不得反向依赖行业包”已经存在一个有意例外:LegalCalculators 直接依赖 Finance。原因是复用通用 TaxBracket/分档引擎,但物理位置使法律计算器依赖“Finance 行业包”。应把真正通用的 bracket primitive 移到中立 calculators 包,或记录例外。

3. 治理 marker 寄宿

IndustryExtensionsModule 不在三个计算程序集,而在已被 Host 加载的 BitzOrcas.Platform.Application。注释明确说三个子程序集不在 API 组合根引用图,因此借寄宿 marker 让 Governance Generator 生成贡献。

这会产生“控制面登记 IndustryExtensions,但数据面没有计算程序集”的状态。Module Registry、Operations 和 Profile catalog 若只看 contribution,可能把能力报告为可用。Readiness 必须同时检查 assembly/reference、所需 wrapper 和规则版本。

4. 没有运行时启用机制

源码没有 AddIndustryExtensions、IModuleServiceConfigurator、Feature Key、Permission Catalog、Health Check 或 Adapter readiness。添加 ProjectReference 后,任何代码都可直接调用 static 方法;没有统一开关。

因此“Profile 显式选择扩展”目前是构建期约定,而不是可审计运行时政策。若模板/Profile 要支持选择,必须让项目生成结果、许可证、Feature 和组合根证据形成闭环。

5. 消费模式

在归属模块中包裹纯计算器
// Wrapper 固定本次业务用途允许的、已审核政策版本。
var policy = await policyStore.GetPublishedAsync(
jurisdiction,
scenario: "finance.income-tax",
occurredOn,
cancellationToken);
// 静态计算器只处理数值;上层保留身份、租户和证据边界。
var raw = IncomeTaxCalculator.CalcIndividualIncomeTax(facts.TaxableIncome);
if (raw.IsFailure)
return raw.Error;
// 结果账本保存输入 hash、政策版本、明细和舍入策略,才能重放。
return await ledger.RecordAsync(
facts.RedactedSnapshot,
policy.Version,
raw.Value,
cancellationToken);

示例中的 policyStore/ledger 是目标集成层,不在当前三个程序集。不要把租户、数据库或认证塞回纯计算函数;由消费模块建立 Application wrapper。

6. Wrapper 的职责

  • 校验调用者有权处理薪资、贷款、合同或拍卖事实;
  • 解析 Tenant、Office、Jurisdiction、Taxpayer/Employee/Contract 类型;
  • 按发生日期选择已发布政策;
  • 校验金额单位、货币、日期和输入证据;
  • 调用纯计算器并生成 breakdown;
  • 保存不可变结果账本和审计;
  • 对敏感字段执行最小化、加密、保留与删除政策;
  • 把 Error code 经 I18n 映射为展示文案;
  • 对外返回“参考/正式”用途与法务免责声明。

7. 无持久化不等于无隐私风险

类库本身不保存数据,也不记录日志,这是良好隔离。但调用输入可能包含收入、扣除、贷款本金、损失、孕产和工龄等高敏感信息。上层若把参数直接写日志、Trace tag 或异常描述,仍会泄漏。

可观测性记录场景、政策版本、Error code、数值范围 bucket 和时延,不记录原始工资/贷款/健康数据。结果 ledger 应根据用途分别执行税务、劳动或合同档案保留规则。

8. Error 边界

Finance/Hr 的 error catalog 允许多个首段前缀,Auction 固定 Auction。Error description 是中文完整句;code 才是稳定合同。

把稳定错误码留给机器合同
var result = MortgageCalculator.CalcEqualInstallmentMonthly(
principal,
annualRate,
years);
// 上层只把 code 写入 Problem Details;原始敏感输入不进入日志。
if (result.IsFailure)
{
diagnostics.Count(result.Error.Code, calculator: "mortgage");
return Errors.Localize(result.Error.Code, languageContext.CurrentLanguage);
}
// 成功后再由调用模块决定是否持久化和审计。
return result.Value;

部分辅助方法直接返回 decimal/int,无法表达校验失败;对外 wrapper 应先验证输入,避免绕过 Result 语义。

9. AOT 声明

源码 XML 多次称零反射、Native AOT 安全。实现确实只用基础数值、Span、List、DateTime 与 ValueObject,没有动态反射/序列化。但“方法可被 AOT 编译”不等于项目已在 Native AOT Host 上构建运行。

GA 证据应包含 AOT publish、trim warnings、调用 smoke 和 public API compatibility。尤其 tuple/ValueObject、Error catalog 和未来规则反序列化需要持续验证。

10. 版本与分发

若三个项目作为商业可选包交付,需要 SemVer、兼容性政策、签名、SBOM、许可证 entitlement、SourceLink、符号包、漏洞扫描和可撤回版本。规则变化与二进制版本不应一一绑定;更适合把引擎版本和 Policy bundle 版本分离。

消费者升级时应能并行保留旧政策,重放历史结果。只替换 DLL 中的 static array 会让历史计算不可重现,也无法判断哪个客户仍使用旧法源。

11. 运行时能力探针

目标 readiness 至少回答:程序集是否加载、wrapper 是否注册、许可证/Feature 是否允许、政策仓是否有当前 Published 版本、法源是否过期、黄金用例是否通过、ledger/outbox 是否可用。

程序集

Application wrapper

License + Feature

Published policy for date

Golden tests + source review

Ready

仅有 Governance contribution 不应让 Ready 变绿。

12. 测试边界

纯类库以单元/属性/黄金测试为主;wrapper 另测 HTTP 授权、租户隔离、Policy resolution、审计和幂等;分发层测 NuGet/AOT/模板/Profile。不要为了“集成测试”给纯计算器引入数据库。

当前 tests 树没有任何 calculator 方法引用,这是最直接的发布阻断项。

13. 检查命令

Terminal window
# 项目引用和 Host 缺席。
rg -n "ProjectReference|Description" src/Platform/IndustryExtensions -g '*.csproj'
rg -n "IndustryExtensions" src/Hosts -g '*.cs' -g '*.csproj'
# DI、权限、Feature、端点与测试当前预期无命中。
rg -n "AddIndustryExtensions|PermissionCatalog|Feature|GenerateEndpoint|\[Fact\]" \
src/Platform/IndustryExtensions tests -g '*.cs'

Industry Extensions 总览 · Finance 计算器 · Auction 与 GA

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%