oh-my-muse/docs/agent-specs/2026-06-17-meta-schema用量投影-review.md
lili d6fc1994e6 docs(meta): meta-schema 用量投影评审版设计(Pull + 按 BC 拆贡献者端口,待确认)
承进度总账 §五A(MetaImpactFacade 置后判定)。基于本会话只读 grounding 调查
(有出处)产出评审版设计,供人类做架构决策——本提交不实现任何代码。

核心结论:
- 根因证实:消费方未持久化 schema 用量(仅 Content planning 存 schema_version、
  无 schema_key;Knowledge/AI 不存)→ MetaImpactFacade 只能诚实 fail-closed
- 架构订正:现 MetaImpactFacade 单接口返 5 维度=单实现者须懂 5 BC 数据、违
  BcBoundaryArchTest 边界门;须拆为 meta-api 定义贡献者端口、各 owner BC 提供适配器
- 推荐 Pull(按需查询贡献者)而非 Push(事件投影):impact preview 低频 admin +
  gate destructive 治理动作、要准确,Pull 无投影漂移/回填/一致性窗口
- 分阶段:P0 端口就位→P1 Content 真实化→P2+ 其余维度;未做维度诚实 unknown 不伪造
- 5 个 open items 待人类定夺(尤:Knowledge/AI 是否真消费 schema、fail-closed 粒度)

台账 §五A 注册指针。待确认方向后再写主 spec + 执行版(数据契约/迁移/IT 验收)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 14:33:15 -07:00

12 KiB

Meta Schema 用量投影建模 —— 评审版设计

版本:v0.1(评审版) · 日期:2026-06-17 · 目标读者:架构决策者(人类) · 类型:评审版(结论先行,无代码细节) 状态:待人类确认架构方向后才进入主 spec / 执行版。本文件不实现任何代码。 关联:进度总账 §五A(MetaImpactFacade 置后判定)、bc-boundaries(本设计须遵守的边界门)。


一、结论先行

  1. 问题本质:Meta 治理写链路(publish/activate/rollback/deprecate 4 端点)在 service 层硬性前置一条 status=succeeded 的 impact preview;而唯一实现 UnavailableMetaImpactFacade 恒抛 META_EXTERNAL_OWNER_UNAVAILABLE,故这 4 端点运行期 100% 阻断。这是诚实 fail-closed(拒绝伪造 impact 数量),非缺陷。
  2. 根因:impact preview 要回答"改这个 schema 版本影响哪些消费方实例、几个命中破坏性改动";但消费方没持久化"谁在用哪个 schema"——Content 的 muse_content_planning_section 仅存 schema_version(整数版本号、schema_key),Knowledge/AI 完全不存 schema 引用。无数据可计数 → facade 只能 fail-closed
  3. 推荐方向(待确认):Pull(按需查询)+ 按 BC 拆分贡献者端口,分阶段按消费 BC 落地。即:
    • 消费方在写入实例时持久化其 schema 用量(至少 schema_key + version,Content 已有 version、补 key);
    • Meta 定义 MetaSchemaUsageContributorApi(meta-api),各消费 BC 实现自己维度的查询(本域查本域 DAL),Meta 侧聚合器实现 MetaImpactFacade 扇出汇总;
    • 现有 MetaSchemaImpactPreviewServiceImpl 调用方不变
  4. 关键架构订正:现有 MetaImpactFacade 单接口返回全部 5 维度(Work/Planning/Knowledge/AI/Export),隐含单一实现者要懂 5 个 BC 的数据 → 违反 BC 边界门(no_business_bc_may_depend_on_another_bc_*)。本设计必须把它拆为"Meta 定义端口、各 owner BC 提供适配器"(与刚落地的 MarketAccountProjectionFacade/MuseAccountRecordProjectionApi 同范式)。
  5. 为何不选 Push(事件投影):见 §五权衡。一句话:impact preview 是低频 admin 操作 + 闸destructive 治理动作,要求准确(不能用滞后的投影门destructive 操作),Pull 无投影漂移/无回填/无最终一致性窗口,且匹配现有同步 facade 契约;Push 的投影表+消费 worker+回填+一致性窗口在此场景是净负担。

二、背景(事实基线,均有代码出处)

详细出处见 grounding 调查(本次会话,只读)。下列为硬事实。

  • 端口:MetaImpactFacade.previewMetaSchemaDraftImpact(schemaKey, draftVersion, draftHash)MetaSchemaImpactSummary{workImpact, planningImpact, knowledgeProjectionImpact, aiContextImpact, exportImpact, totalAffectedProjectionCount},位于 meta.application.facade。唯一实现 UnavailableMetaImpactFacadeMETA_EXTERNAL_OWNER_UNAVAILABLE(1_042_001_004)
  • 硬门禁:MetaSchemaServiceImpl 的 publish/activate/rollback/deprecate 均前置 requireImpactPreview(需 status=succeededmuse_meta_impact_preview 记录,否则 META_IMPACT_PREVIEW_REQUIRED 1_042_001_002)。
  • impact 语义:每个消费维度的定量快照——受影响实例数 + 命中破坏性改动(字段移除/可见性改变/投影需重建)的实例数。
  • 消费方持久化现状(根因):Content muse_content_planning_section.schema_version(INT,无 schema_key 列、无用量表);Knowledge/AI 无任何 schema 引用持久化。
  • 已有数据模型:muse_meta_impact_preview(JSONB 存 impact_summary/error/source_snapshot + status,一次性预览快照、非累计用量);无任何 usage/projection 累计表;无独立 usage/export 模块。
  • 可复用事件基建:Content 有成熟幂等 outbox(ContentEventPublishOutboxServiceImpl:insertIgnore + worker claim + 重试);AI/Knowledge 有 outbox 接口;EventsPublishApi 跨 BC 事件。

三、目标 / 非目标

目标

  • 让 4 个 Meta 治理端点从"恒 fail-closed"变为"基于真实消费用量给出 impact preview 后可放行",且绝不伪造 impact 数量。
  • 真实化路径遵守 BC 边界门(Meta 不直连他域 DAL / application)。
  • 可分阶段交付:每阶段一个消费维度真实化,未真实化维度保持诚实 fail-closed 或显式 0/unknown(不伪造)。

非目标(本轮)

  • 不做实时/全量用量大盘或运营报表。
  • 不引入独立 muse-module-usage/export 模块(除非评审认定必要)。
  • 不改 MetaSchemaImpactPreviewServiceImpl 的对外语义与现有 4 端点的 API 契约。
  • 不在前端做 admin 可视化(meta 治理属 admin 侧、用户价值低,排后)。

四、推荐方案(Pull + 按 BC 拆分贡献者端口)

4.1 架构总览

flowchart TD
    A[AdminMetaSchemaController\npublish/activate/rollback/deprecate] --> B[MetaSchemaServiceImpl.requireImpactPreview]
    B --> C[MetaSchemaImpactPreviewServiceImpl]
    C --> D[MetaImpactFacade 聚合器实现\nmeta-server]
    D -->|fan-out 查询| E1[Content 贡献者适配器\ncontent-server 查本域 DAL]
    D -->|fan-out 查询| E2[Knowledge 贡献者适配器\nknowledge-server]
    D -->|fan-out 查询| E3[AI 贡献者适配器\nai-server]
    D -->|聚合| F[MetaSchemaImpactSummary]
    F --> G[(muse_meta_impact_preview\n仍存快照)]
    subgraph 端口契约 meta-api
      P[MetaSchemaUsageContributorApi\nMeta 定义、各 owner BC 实现]
    end
    E1 -. implements .-> P
    E2 -. implements .-> P
    E3 -. implements .-> P
    D -. 依赖 .-> P

4.2 两层改造

  • 基础层(各消费 BC,特征工程):在实例写入时持久化其 schema 用量,使"哪些实例用了 schemaKey X 的哪些字段"可被本域查询。Content 已有 schema_version,补 schema_key(+必要时字段使用快照);Knowledge/AI 视其是否真消费 schema 决定是否纳入(见 open item 1)。
  • 端口层(契约):meta-api 定义 MetaSchemaUsageContributorApi(本进程内 Bean 端口,参照 MuseContentWorkOwnerApi 先例,非 @FeignClient);各 owner BC 在 *-server 实现自己维度的计数/破坏性分析(只读本域 DAL);meta-server 的 MetaImpactFacade 真实聚合器扇出各贡献者、组装 MetaSchemaImpactSummary

4.3 分阶段(价值/可验证性优先)

阶段 内容 完成后效果
P0 meta-api 定义贡献者端口 + meta-server 聚合器(未接消费方时对各维度显式 unknown/fail-closed,绝不 0 伪装) 端口就位,行为等价现状但架构可扩展
P1 Content(work + planning)真实化:补 schema_key 持久化 + Content 实现贡献者适配器 Content 维度真实计数,治理端点对"仅 Content 受影响"可放行
P2+ Knowledge / AI / Export 逐维度真实化(各自 owner 出适配器) 其余维度逐步真实

每阶段验收=该维度真实 PG IT(种真实消费实例→preview 返回真实计数;负路径未接入维度 fail-closed 不伪造)。


五、关键权衡:Pull vs Push

维度 Pull(推荐:按需查询贡献者) Push(事件投影:消费方发用量事件→Meta 投影表)
准确性 实时准确,直接查源 最终一致,有滞后窗口——用滞后投影 gate destructive 治理动作有风险
新增数据模型 无新累计表(复用 impact_preview 快照) muse_meta_schema_usage_projection + 消费 worker
历史数据 无需回填(直接扫源) 需回填既有实例,否则投影不全
BC 边界 各 BC 查本域(合规) 各 BC 发事件 + Meta 消费(合规),但组件更多
成本/复杂度 低(匹配现有同步 facade 契约) 高(发布点+outbox+worker+回填+一致性)
频率匹配 impact preview 低频 admin,扫描成本可接受 投影适合高频读;此场景高频读不存在
共同前提 两者都需消费方持久化 schema 用量(根因不可绕过)

结论:在"低频、要准确、gate destructive 操作"的 impact preview 场景,Pull 显著优。Push 的优势(高频读、解耦)在此不构成价值,反引入投影漂移与回填负担。故推荐 Pull。(若未来出现"运营用量大盘"等高频读需求,可在 Pull 之上另建投影,不与本设计冲突。)


六、Blast Radius / 兼容性

  • meta:新增 meta-api 端口 + meta-server 聚合器实现替换 UnavailableMetaImpactFacade(经 @ConditionalOnMissingBean/@Primary 平滑替换,参照 facade 替换先例)。MetaSchemaImpactPreviewServiceImpl 与 4 端点 API 契约不变
  • content(P1):新增 schema_key 持久化=Flyway 新增迁移(只增不改) + 写入点补字段 + 贡献者适配器(只读本域)。对既有 planning 写链路低侵入。
  • knowledge/ai(P2+):仅在确属 schema 消费方时改;否则该维度贡献者返回 unknown(诚实)。
  • DB 迁移:每阶段独立 V<n>__*.sql(只增列/表,不改历史);Content 既有行 schema_key 为空→该维度对"历史无 key 行"按 unknown 计(不伪造),随写入逐步补全。
  • 回滚:端口未接消费方时聚合器 fail-closed=回到现状(治理端点阻断),无数据损坏面。

七、风险

风险 说明 缓解
破坏性分析需字段级用量 仅计数不够,要判"字段被移除影响几个"需消费方记录用到哪些字段 P1 评估 Content planning 的 content JSON 是否足以反推字段用量;不足则补字段使用快照
版本快照一致性 消费方仅记 version、不记 key/hash,Meta 版本变更后难追溯旧版影响 基础层补 schema_key(+可选 draft_hash 快照),使消费实例自证用的哪个 schema
跨 BC 扇出延迟 preview 同步扇出多 BC 低频 admin 可接受;贡献者查询走本域索引;超时则该维度 unknown(不阻塞他维度、不伪造)
维度归属不清 Knowledge/AI 是否真消费 schema 未证实(grounding 显示其不持久化) open item 1:先证实再决定是否纳入,避免给不消费 schema 的 BC 强加端口
特征工程蔓延 多 BC 改写入链路 严格分阶段、每阶段独立可验收;未做维度诚实 fail-closed

八、验收标准(达成定义)

  • 端口层:MetaSchemaUsageContributorApi 在 meta-api;聚合器替换 Unavailable 后 BcBoundaryArchTest 仍 0 违例(Meta 不直连他域 DAL/application)。
  • P1(Content):真实 PG IT——种真实 planning/work 实例(带 schema_key)→ previewMetaSchemaDraftImpact 返回真实 Content 计数;无消费实例→0(真实 0,非伪造);未接入维度→unknown/fail-closed;治理端点在"仅 Content 受影响"下可走通 preview→publish。
  • 反假绿:未持久化 schema_key 的历史行不被计入"已知用量"(按 unknown),杜绝把"没数据"伪装成"0 影响"。

九、Open Items(需人类/后续确认)

  1. Knowledge/AI/Export 是否真消费 MetaSchema? grounding 显示三者均不持久化 schema 引用。需确认:impact summary 的这 3 维度是真实业务需求,还是 over-modeled 的 VO?若不消费,贡献者端口只需 Content(+视情况 Export),大幅缩小范围。
  2. 破坏性分析的精度要求:impact 只需"受影响实例数",还是必须"字段级破坏(移除/可见性)"?后者决定基础层是否要存字段使用快照(成本差异大)。
  3. 是否接受分阶段期间"部分维度 unknown"的 preview 放行治理动作? 即:只要已接入维度真实、未接入维度诚实 unknown,是否允许 admin 据此 publish?(关乎 fail-closed 的粒度策略。)
  4. schema_key 回填策略:历史 planning 行无 key,是否需要一次性回填脚本(若 version→key 可推断),还是只对新写入生效、历史按 unknown。
  5. 端口命名/归属与现有 MetaImpactFacade 的关系(保留 facade 作聚合门面 vs 直接重构)。

下一步:请就 §一.3 方向、§五 Pull 选型、§九 open items(尤其 #1 维度归属、#3 fail-closed 粒度)给意见。确认后再写主 spec + 执行版(含数据契约、迁移、IT 验收)。