BLOGE
0.9.8-RC1在线版 · 事实校验 2026-09-15 · English
第 23 章 —— 业务正确性不等于测试通过
本章承诺: 你会把“代码能跑”“Graph 成功”“业务结果满足”和“证据可以用于发布”拆成四个问题,并知道
PASS为什么不能直接写成“可以发布”。
学习目标
- 区分语法、执行、业务和证据四种正确性。
- 建立
VerificationStatus、EvidenceTrust、ClaimCapability三条独立轴。 - 找到业务负责人、BLOGE 开发者、verifier 和发布负责人的责任边界。
- 用一个最小 Scenario 运行真实 BLOGE,而不是只比较最终
GraphResult。
先看业务问题
贷款运营负责人给出了一组可验收的结果:低风险申请自动批准,高风险申请自动拒绝,边界申请进入人工复核;放款失败时必须按政策重试、回退或补偿。
这不是一句“测试通过”可以概括的要求。先看本章的关系图:
图上最重要的不是箭头数量,而是三条轴不能互相代替:
VerificationStatus ——回答这次 Suite / Case 发生了什么;不能证明证据是否绑定到声明的源码与运行输入。
EvidenceTrust ——回答结果与哪些源码、Scenario、Policy、Fixture 和 runtime 绑定;不能证明业务政策本身是否正确。
ClaimCapability ——回答证据最多支持本地开发、团队门禁、治理门禁还是发布;不能证明业务 verdict 是否为 PASS。
先把四种“正确”分开
从第 18 章的 Graph 测试开始,读者已经能验证节点状态、执行顺序和 GraphResult。这些能力仍然重要,但它们只覆盖了完整问题的一部分。
语法正确 ——.bloge 能否解析、编译?使用 parser、compiler 和 DSL test;不代表业务分支选对。
执行正确 ——节点是否按依赖执行、错误是否传播?使用 GraphTestRunner、GraphResult;不代表业务标准答案满足。
业务正确 ——riskDecision 是否为 auto_approve?使用 Scenario + BUSINESS_CONTRACT;不代表源码和运行身份可复核。
证据可用 ——这次结果能否支持团队或发布决策?使用 source-bound reader、VerificationClaims;不替业务负责人批准政策。
一个 GraphResult.isSuccess() 只说明图执行没有按引擎语义失败。它不能自动说明一个拒绝分支没有被错误地绕过,也不能说明测试使用的外部 effect 与生产合同一致。
第一个 verifier 入口
ScenarioVerifier.verify(Path) 是单 Suite 的最短入口。实际 starter 使用 BlogeScenarioTests.fromDirectory(...) 把同一目录下的 Scenario 变成 JUnit dynamic tests;两者都经过真实 parser、compiler 和 engine。
下面的片段只展示入口形状,bootstrap、projectRoot 和 Policy 必须替换成自己的项目事实:
ScenarioVerifier verifier = ScenarioVerifier.builder()
.bootstrap(caseContext -> VerificationEnvironment.controlled(operatorRegistry))
.projectRoot(projectRoot)
.policy(projectRoot.resolve("src/test/bloge/verification-policy.yaml"))
.build();
VerificationReport report = verifier.verify(
projectRoot.resolve("src/test/bloge/scenarios/loan-approval.scenario.yaml"));
assertEquals(VerificationStatus.PASS, report.status());
这里的 PASS 只回答“声明的 Suite 在这次运行中满足了它的 Expectation”。如果没有 source-bound artifact、receipt 和独立 reader,不能顺手把它升级为 SOURCE_BOUND 或 RELEASE_QUALIFIED。
同一份 PASS,读出三种错结论
假设贷款报告只有这些事实:
suiteId=loan-approval-decisions
caseId=auto-approve
status=PASS
reasonCodes=[]
三个读者可能把一份诚实报告升级成三句不诚实的话:
| 错误解读 | 缺了什么 | 正确读法 |
|---|---|---|
| “所有申请人的决策规则都正确。” | Suite 之外的 Case 和 sensitivity 挑战 | 这个 Case 满足了声明的 Expectation。 |
| “结果一定来自审阅过的 commit。” | seal、源码摘要、worktree identity 和 reader 结果 | 单独的 report object 仍是 UNVERIFIED。 |
| “这个版本可以发布。” | Policy continuity、治理 receipt、comparison 和 release attestation | PASS 本身推不出发布能力。 |
这不是抽象的谨慎。RC1 有意让三条轴能够彼此不同。VerificationReportWriterTest.rechecksArtifactBytesAfterThePublicationGuard 先构造一份 PASS report,再让 publication guard 把 summary 扩大到 4096 字节以上;writer 最终得到 INCOMPLETE / RESOURCE_LIMIT_EXCEEDED,并保持输出目录为空。业务 verdict 不能覆盖出版边界失败。
VerificationContractEvidenceTest 从另一侧封口:PASS Case 不能同时携带失败原因,FAIL Case 不能声明 satisfied;聚合后的 Suite、Case、Requirement 和 assurance identity 必须一致。2026-09-14 在 BLOGE commit cc38fbe5 上,这两个聚焦测试类共运行 5 tests,0 failures,0 errors,0 skips。
所以阅读顺序必须固定:
- 先读
VerificationStatus:声明的合同在这次运行里是否满足? - 再读
EvidenceTrust:证据绑定了哪些不可变输入? - 最后读
ClaimCapability:完整证据最多能支持哪类决策?
开发阶段停在第一步没有问题;把第一步改名成第三步,才是问题。
三个容易出现的“假绿”
跳过 manual_review ——普通测试可能只看到最终对象仍然是 approved。业务验证必须分别断言业务输出和人工路径;跳过节点属于结构事实。
隐藏 fallback ——普通测试可能只看到 Graph 仍然 SUCCESS。业务验证必须记录 retry disposition、fallback 和 effect 处置,再确认这是政策允许的降级。
直接调用 Operator ——普通测试可能只看到 Operator 单测 PASS。业务验证还要让 Scenario 进入真实 parser/compiler/engine,并限制未声明 effect。
这不是把 JUnit 判定为无用。正确的做法是让每一层回答自己擅长的问题,再把结果按证据边界组合起来。
四类角色,各自提供什么
业务负责人 ——提供标准答案、边界 Case、Requirement、可接受失败和 Oracle 来源;不把绿色测试直接批准为发布。
BLOGE 开发者 ——提供 DSL、Operator、Scenario、Policy、Fixture 和 bootstrap;不用实现代码复制标准答案。
verifier / 平台 ——提供受控执行、观察、reason code、artifact、seal 和 reader;不修改业务政策来消除失败。
发布负责人 ——提供 commit、worktree、receipt、ClaimCapability 和缺口;不把 AUTHORING 改写为 RELEASE_QUALIFIED。
本章实验:把一个“绿测试”拆开
- 选一个只断言
GraphResult的贷款 Case,补一个BUSINESS_OUTPUT断言。 - 再补一个分支跳过或调用事实的
STRUCTURAL_CONTRACT断言。 - 列出这两个断言仍然没有证明的两件事,例如源码未绑定、外部服务未被独立复核。
- 将报告状态、证据可信度和 claim 能力写成三列,不允许用一个词覆盖三列。
实验停止条件:如果输入、Policy 或 bootstrap 不完整,报告应保持 INVALID 或 INCOMPLETE;不要通过重试把合同问题改写成业务 FAIL 以外的绿灯。
现实迁移:药品放行流程
在医院药房里,“流程执行完成”只说明处方走完了声明步骤,不代表剂量满足已批准 规则、结果来自已审阅药品目录,也不代表药师可以放行。把 graph status、剂量 Expectation、与药品目录绑定的 evidence、放行权限分别映射到本章四层。如果一个 绿色徽章同时承担两个以上责任,就先停止发布判断。
实验验收卡
- 预期与观察: 同一 PASS 分别读取 verdict、evidence trust 和 claim capability。
- 失败与恢复: 删除 guard 或污染 evidence;恢复证据后重读三轴。
- 证明边界: 证明受控 Case 的声明,不证明发布已批准。
- 练习合同: 一个绿色 Case;只攻击一条证据边界;交付三轴读数;结论不越过 capability 即停止。
本章小结
可靠的 FAIL 能指出一个业务合同确实没有满足;没有来源绑定的 PASS 只说明一次运行看起来成功。下一章把这条原则落到 starter 的两个 Suite、七个 Case 上。
Coding Agent: Open the versioned task guide.