feat(content/knowledge/ai): B 四维 VERIFIED_ZERO 贡献者 + 机械化断言[P2]

5 维度贡献者齐全(Planning REAL_COUNT 已落,本次补四个 VERIFIED_ZERO):

- Work/Export(content):work 仅绑 schemaId 不存字段值、ExportTaskDO 零 schema 引用→VERIFIED_ZERO;机械化断言 DO 无动态字段值列(漂移即失败)。

- KnowledgeProjection(knowledge)/AIContext(ai):零 meta 引用(projection 是 CQRS 读模型、metadataFields 是向量库)→VERIFIED_ZERO;knowledge/ai-server 加 meta-api 依赖;机械化断言贡献者无数据依赖字段。

验证:content 9/9(Verified 4+Planning 5)、knowledge 2/2、ai 2/2。下一步:单体装配验证 RealMetaImpactFacade 收齐 5 维度、all-real 不再 fail-closed。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
lili 2026-06-21 01:54:06 -07:00
parent 94a23797ff
commit f3f7a0962f
9 changed files with 269 additions and 0 deletions

View File

@ -48,6 +48,12 @@
<artifactId>muse-module-ai-api</artifactId>
<version>${revision}</version>
</dependency>
<!-- Meta Schema 用量投影:实现 MetaSchemaUsageContributor 端口AIContext 维度 VERIFIED_ZERO -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>muse-module-meta-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>muse-module-events-api</artifactId>

View File

@ -0,0 +1,30 @@
package cn.iocoder.muse.module.ai.application.impact;
import cn.iocoder.muse.module.meta.api.impact.MetaImpactDimension;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaDimensionImpact;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaImpactProbe;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaUsageContributor;
import org.springframework.stereotype.Service;
/**
* AIContext 维度 Meta Schema 用量贡献者ai
*
* <p>ai 全域零 Meta Schema 引用AI 上下文 / prompt 构建不读 schema 字段可见性aiContext
* "metadataFields" 是向量库Redis/Milvus字段定义 Meta Schemaschema aiContext 可见性仅在 meta 域定义
* 不在 ai 实例持久化运行时注入不留痕 已验证真实 0
* 若未来 AI 运行时按 schema aiContext 裁剪并留痕计数须重评 execution §.5
* 机械化断言见 {@code AiContextUsageContributorTest}</p>
*/
@Service
public class AiContextUsageContributor implements MetaSchemaUsageContributor {
@Override
public MetaImpactDimension dimension() {
return MetaImpactDimension.AI_CONTEXT;
}
@Override
public MetaSchemaDimensionImpact previewDimensionImpact(MetaSchemaImpactProbe probe) {
return MetaSchemaDimensionImpact.verifiedZero(MetaImpactDimension.AI_CONTEXT);
}
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.muse.module.ai.application.impact;
import cn.iocoder.muse.module.meta.api.impact.MetaImpactDimension;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaDimensionImpact;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaImpactProbe;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
/**
* AIContext 维度 VERIFIED_ZERO 贡献者测试 + 机械化漂移断言
*/
class AiContextUsageContributorTest {
@Test
void isVerifiedZero() {
AiContextUsageContributor contributor = new AiContextUsageContributor();
assertEquals(MetaImpactDimension.AI_CONTEXT, contributor.dimension());
MetaSchemaDimensionImpact impact = contributor.previewDimensionImpact(
new MetaSchemaImpactProbe(1L, "k", 1, "h", Set.of("a"), Set.of(), Set.of()));
assertEquals(MetaSchemaDimensionImpact.RealityKind.VERIFIED_ZERO, impact.realityKind());
assertEquals(0, impact.affectedInstanceCount());
}
@Test
void hasNoDataDependency() {
// 机械化断言VERIFIED_ZERO 贡献者不得注入数据依赖一旦出现字段说明开始读 ai 数据须改 REAL_COUNT 重评
long fields = Arrays.stream(AiContextUsageContributor.class.getDeclaredFields())
.filter(f -> !f.isSynthetic()).count();
assertEquals(0, fields, "VERIFIED_ZERO 贡献者出现字段依赖,疑似开始消费 schema须重新评估真实计数");
}
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.muse.module.content.application.impact;
import cn.iocoder.muse.module.meta.api.impact.MetaImpactDimension;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaDimensionImpact;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaImpactProbe;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaUsageContributor;
import org.springframework.stereotype.Service;
/**
* Export 维度 Meta Schema 用量贡献者content
*
* <p>{@code ExportTaskDO} schema 引用导出按 work 正文内容生成 schema 字段投影
* schema 侧的 exportable 可见性仅在 meta 域定义不在 export 任务实例持久化已验证真实 0
* 若未来导出改为按 schema exportable 字段裁剪并记录字段级用量须改置 meta-server 真实计数
* execution § Export 机械化断言见 {@code ContentVerifiedZeroContributorTest}</p>
*/
@Service
public class ContentExportUsageContributor implements MetaSchemaUsageContributor {
@Override
public MetaImpactDimension dimension() {
return MetaImpactDimension.EXPORT;
}
@Override
public MetaSchemaDimensionImpact previewDimensionImpact(MetaSchemaImpactProbe probe) {
return MetaSchemaDimensionImpact.verifiedZero(MetaImpactDimension.EXPORT);
}
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.muse.module.content.application.impact;
import cn.iocoder.muse.module.meta.api.impact.MetaImpactDimension;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaDimensionImpact;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaImpactProbe;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaUsageContributor;
import org.springframework.stereotype.Service;
/**
* Work 维度 Meta Schema 用量贡献者content
*
* <p>work 仅通过 work_schema_id 绑定 schema关联引用不在 work 表持久化任何 schema 字段值
* / schema 字段不破坏 work 实例数据故为已验证真实 0 unknown
* 机械化断言见 {@code ContentVerifiedZeroContributorTest}work 域不得出现承载 schema 字段值的动态列
* 漂移即测试失败强制重评 VERIFIED_ZERO</p>
*/
@Service
public class ContentWorkUsageContributor implements MetaSchemaUsageContributor {
@Override
public MetaImpactDimension dimension() {
return MetaImpactDimension.WORK;
}
@Override
public MetaSchemaDimensionImpact previewDimensionImpact(MetaSchemaImpactProbe probe) {
return MetaSchemaDimensionImpact.verifiedZero(MetaImpactDimension.WORK);
}
}

View File

@ -0,0 +1,70 @@
package cn.iocoder.muse.module.content.application.impact;
import cn.iocoder.muse.module.content.dal.dataobject.ExportTaskDO;
import cn.iocoder.muse.module.content.dal.dataobject.WorkDO;
import cn.iocoder.muse.module.meta.api.impact.MetaImpactDimension;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaDimensionImpact;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaImpactProbe;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.*;
/**
* Work / Export 维度 VERIFIED_ZERO 贡献者测试 + 机械化漂移断言
*
* <p>机械化断言一旦 work / export 实例表出现承载 schema 字段值的动态列说明该域开始消费 schema
* VERIFIED_ZERO 假设失效断言失败以强制重新评估防止静默漂移放行错误的 0</p>
*/
class ContentVerifiedZeroContributorTest {
/** 承载「按 schema fieldKey 的字段值」的典型列名;出现任一即视为该域开始消费 schema。 */
private static final Set<String> DYNAMIC_FIELD_VALUE_COLUMNS =
Set.of("dynamicFields", "fieldValues", "customFields", "metaFieldValues", "contentPayload", "schemaFields");
private MetaSchemaImpactProbe anyProbe() {
return new MetaSchemaImpactProbe(100L, "work_core", 2, "hash",
Set.of("title"), Set.of("desc"), Set.of("tag"));
}
@Test
void workContributor_isVerifiedZero() {
ContentWorkUsageContributor contributor = new ContentWorkUsageContributor();
assertEquals(MetaImpactDimension.WORK, contributor.dimension());
MetaSchemaDimensionImpact impact = contributor.previewDimensionImpact(anyProbe());
assertEquals(MetaSchemaDimensionImpact.RealityKind.VERIFIED_ZERO, impact.realityKind());
assertEquals(0, impact.affectedInstanceCount());
assertEquals(0, impact.fieldRemovedInstanceCount());
}
@Test
void exportContributor_isVerifiedZero() {
ContentExportUsageContributor contributor = new ContentExportUsageContributor();
assertEquals(MetaImpactDimension.EXPORT, contributor.dimension());
MetaSchemaDimensionImpact impact = contributor.previewDimensionImpact(anyProbe());
assertEquals(MetaSchemaDimensionImpact.RealityKind.VERIFIED_ZERO, impact.realityKind());
assertEquals(0, impact.affectedInstanceCount());
}
@Test
void workDO_hasNoDynamicFieldValueColumn() {
assertNoDynamicFieldValueColumn(WorkDO.class);
}
@Test
void exportTaskDO_hasNoDynamicFieldValueColumn() {
assertNoDynamicFieldValueColumn(ExportTaskDO.class);
}
private void assertNoDynamicFieldValueColumn(Class<?> doClass) {
Set<String> fieldNames = Arrays.stream(doClass.getDeclaredFields())
.map(Field::getName).collect(Collectors.toSet());
Set<String> hit = fieldNames.stream().filter(DYNAMIC_FIELD_VALUE_COLUMNS::contains).collect(Collectors.toSet());
assertTrue(hit.isEmpty(),
doClass.getSimpleName() + " 出现动态字段值列 " + hit + ";该域疑似开始消费 schemaVERIFIED_ZERO 假设失效,须重新评估真实计数");
}
}

View File

@ -22,6 +22,12 @@
<artifactId>muse-module-knowledge-api</artifactId>
<version>${revision}</version>
</dependency>
<!-- Meta Schema 用量投影:实现 MetaSchemaUsageContributor 端口KnowledgeProjection 维度 VERIFIED_ZERO -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>muse-module-meta-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>muse-module-events-api</artifactId>

View File

@ -0,0 +1,29 @@
package cn.iocoder.muse.module.knowledge.application.impact;
import cn.iocoder.muse.module.meta.api.impact.MetaImpactDimension;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaDimensionImpact;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaImpactProbe;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaUsageContributor;
import org.springframework.stereotype.Service;
/**
* KnowledgeProjection 维度 Meta Schema 用量贡献者knowledge
*
* <p>knowledge 全域零 Meta Schema 引用 "projection" 是跨来源 CQRS 读模型
* MuseKnowledgeSourceBindingProjection Meta Schema 字段投影无关KB 自有 visibilityPolicy 是知识域概念
* schema 可见性 / schema 字段不影响 knowledge 任何实例 已验证真实 0 unknown
* 机械化断言见 {@code KnowledgeProjectionUsageContributorTest}本贡献者无数据依赖字段漂移即失败</p>
*/
@Service
public class KnowledgeProjectionUsageContributor implements MetaSchemaUsageContributor {
@Override
public MetaImpactDimension dimension() {
return MetaImpactDimension.KNOWLEDGE_PROJECTION;
}
@Override
public MetaSchemaDimensionImpact previewDimensionImpact(MetaSchemaImpactProbe probe) {
return MetaSchemaDimensionImpact.verifiedZero(MetaImpactDimension.KNOWLEDGE_PROJECTION);
}
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.muse.module.knowledge.application.impact;
import cn.iocoder.muse.module.meta.api.impact.MetaImpactDimension;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaDimensionImpact;
import cn.iocoder.muse.module.meta.api.impact.MetaSchemaImpactProbe;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
/**
* KnowledgeProjection 维度 VERIFIED_ZERO 贡献者测试 + 机械化漂移断言
*/
class KnowledgeProjectionUsageContributorTest {
@Test
void isVerifiedZero() {
KnowledgeProjectionUsageContributor contributor = new KnowledgeProjectionUsageContributor();
assertEquals(MetaImpactDimension.KNOWLEDGE_PROJECTION, contributor.dimension());
MetaSchemaDimensionImpact impact = contributor.previewDimensionImpact(
new MetaSchemaImpactProbe(1L, "k", 1, "h", Set.of("a"), Set.of(), Set.of()));
assertEquals(MetaSchemaDimensionImpact.RealityKind.VERIFIED_ZERO, impact.realityKind());
assertEquals(0, impact.affectedInstanceCount());
}
@Test
void hasNoDataDependency() {
// 机械化断言VERIFIED_ZERO 贡献者不得注入数据依赖一旦出现字段说明开始查 knowledge 数据须改 REAL_COUNT 重评
long fields = Arrays.stream(KnowledgeProjectionUsageContributor.class.getDeclaredFields())
.filter(f -> !f.isSynthetic()).count();
assertEquals(0, fields, "VERIFIED_ZERO 贡献者出现字段依赖,疑似开始消费 schema须重新评估真实计数");
}
}