Online edition for BLOGE
0.9.8-RC1· facts verified 2026-09-15 · 中文
Chapter 32 — Change Attribution, Maven, and Release Decisions
Chapter promise: You will isolate one change axis, run the smallest honest Maven ladder, and decide whether the resulting evidence supports local diagnosis, a team gate, governed approval, or a release decision.
Learning goals
- Separate a DSL graph change, a BLOGE toolchain upgrade, and a business-code change.
- Distinguish an observed difference from a difference that BLOGE can attribute.
- Choose Maven commands by the claim you need, not by how green the console looks.
- Preserve the receipts and external attestation needed for a release decision.
The upgrade changed the answer—but what caused it?
The loan team upgrades to BLOGE 0.9.8-RC1. The boundary application now enters manual review instead of auto-approval. During the same branch, someone also edits the risk Operator. A before/after test can show a difference, but it cannot assign that difference to either change.
Attribution requires a controlled experiment: change one declared axis and freeze every material non-axis fact. If the Operator and runtime change together, stop at diagnosis, split the experiment, and run two comparisons.
Split the upgrade into two receipts
“Upgrade branch” is not a valid change axis. It mixes source edits, graph edits, dependency resolution, and runtime bytes. The loan team therefore creates two experiments from one common baseline:
| Experiment | The only changed fact | Facts that must stay frozen | Honest result |
|---|---|---|---|
A — DSL_GRAPH | baseline graph → candidate graph | BLOGE runtime, Scenario, Policy, Fixture, bootstrap, registry, profile | graph difference is attributable, or COMPARISON_INPUT_DRIFT |
B — BLOGE_TOOLCHAIN | baseline BLOGE class inventory → RC1 inventory | business classpath, graph and declared inputs, Java launcher/protocol | attributable only with BLOGE_VERIFIED observations |
Experiment A in attributesAnObservedBusinessRegressionToTheDslGraphAxis changes only the candidate graph's decision input. Both sides execute once; the candidate report is FAIL, the change code includes OUTPUT_DIGEST_CHANGED:approve-low-risk/decision, the comparison is attributable, and it is not equivalent.
Its control attributesOnlyDslGraphChangeWhenEveryFrozenExecutionFactMatches changes graph bytes while preserving the observed contract. It is both attributable and equivalent. Thus attributable and equivalent are independent questions.
Experiment B in blogeOwnedChildExecutesTheFrozenScenarioBeforeAttributingTheToolchainAxis keeps business classes and declared inputs fixed, changes the runtime inventory, and receives BLOGE_VERIFIED observations from two terminated child JVMs. The result is attributable, observationally equivalent, equivalent, and published as SOURCE_BOUND. Copying that artifact outside its bound project location produces COMPARISON_SOURCE_BINDING_DRIFT.
Now attack one frozen fact: businessClasspathMutationIsReportedAsInputDrift changes a business classpath marker during the toolchain experiment. The result becomes COMPARISON_INPUT_DRIFT and attributable=false. The runtime upgrade may still be interesting, but this run can no longer say it caused the observation.
Compare one DSL graph axis
For a graph-only change, both executions reuse one canonical Scenario and the verifier's source-bound environment:
ComparisonPlan plan = ComparisonPlan.dslGraph(
"loan-risk-threshold-v3",
scenarioPath,
baselineGraphPath,
candidateGraphPath);
VerificationAttributedComparisonEvidence evidence =
verifier.compareEvidence(plan);
compareEvidence(...) publishes only when the DSL_GRAPH axis is attributable. It freezes the Scenario, Policy, Fixture, selected Cases, execution profile, bootstrap, Operator registry, service identity, governance inputs, and Git source binding. A drifted non-axis fact produces COMPARISON_INPUT_DRIFT and leaves only an in-memory diagnostic.
attributable() answers whether the observed change belongs to the declared axis. equivalent() is stricter: attribution must hold, both sides must pass, and their payload-free observations must match. Two equal outputs do not prove the candidate is better; they only report no observed regression within this contract.
Compare two BLOGE toolchains with frozen business code
A runtime upgrade needs two terminated child JVMs and one shared business runtime:
ToolchainBusinessRuntime business = ToolchainBusinessRuntime.of(
businessClasspath,
"com.acme.loan.LoanApprovalVerificationBootstrap");
ToolchainComparisonPlan plan = ToolchainComparisonPlan.blogeVerification(
"bloge-0.9.7-to-0.9.8-rc1",
inputs,
business,
ToolchainEndpoint.blogeVerifier("baseline", baselineToolchain),
ToolchainEndpoint.blogeVerifier("candidate", candidateToolchain));
VerificationToolchainComparisonEvidence evidence =
PairedExecutionCoordinator.builder()
.projectRoot(projectRoot)
.build()
.compareEvidence(plan, outputRoot);
inputs must include scenario, policy, and every referenced DSL, Fixture, and Oracle file. Both children use the coordinator's Java launcher, the same ordered business classpath, and different BLOGE class inventories. The fixed BLOGE child reconstructs the project-relative files and runs a real ScenarioVerifier.
A custom javaMain(...) adapter is only PROVIDER_ATTESTED. It may report observationallyEquivalent(), but it cannot make attributable() or equivalent() true. Only blogeVerifier(...) gives the coordinator BLOGE_VERIFIED observations strong enough for attribution.
Run the Maven ladder that matches the question
-
Focused story check — fast feedback. Run the three loan starter tests. Eleven passing tests cover the selected story, not the whole Reactor.
mvn -pl bloge-starter-loan-approval -am \-Dtest='LoanApprovalApplicationTest,LoanApprovalBusinessScenarioTest,LoanApprovalOperatorFlowTest' \-Dsurefire.failIfNoSpecifiedTests=false test -
Install the Preview plugin from a source checkout when needed. If
0.9.8-RC1is not available from your Maven repository, install it from the same source snapshot.invoker.skipskips only the plugin's own integration fixtures; it does not replace the complete Reactor check below.mvn -pl bloge-maven-plugin -am install \-DskipTests -Dinvoker.skip=true -
Publish customer-module verification artifacts — Preview. In the customer module, keep compilation and the goal in one Maven invocation. The goal reads
.blogeverify.yamland writes the configured report directory.mvn test-compile \com.leanowtech.bloge:bloge-maven-plugin:0.9.8-RC1:verifyA
PASShere is still bounded by the config, source binding, receipt custody, and evidence capability. Keep the receipt outside the mutable artifact directory.Known RC1 boundary: this book's loan starter places its bootstrap under
com.leanowtech.bloge.starter.*. The0.9.8-RC1plugin classloader mistakes that prefix for plugin-owned code, so the goal fails closed for this starter withTEST_CLASSPATH_UNAVAILABLE. This is not a Scenario failure; the runnable starter entry point is the JUnit check in step 1. Plugin Invoker fixtures cover Plain Java and Spring bootstraps in ordinary customer namespaces. Until the classloader boundary is fixed, do not present the starter as a successful artifact-publication example. -
Check the complete Java build.
mvn clean installThis checks the Reactor build; it does not create missing business Requirements or approve an Oracle.
verify-reactoris a separate Preview path that requires schema-v2 per-module governance configuration and direct modules in one Git worktree. The loan starter configuration in this book does not claim that Reactor evidence.
Turn evidence into a decision
Read the highest supported ClaimCapability, then keep its boundary visible:
- Local diagnosis —
AUTHORING: the comparison is not source-bound, one axis is not isolated, or required continuity evidence is absent. Fix the experiment before discussing causality. - Team gate —
TEAM_GATE: source binding, Policy continuity, replay assurance, and CI-safe execution are present. This supports team integration, not governed business approval. - Governed approval —
GOVERNED_GATE: trusted Project evidence also satisfies versioned Requirements and required Oracle provenance. - Release decision —
RELEASE_QUALIFIED: governed Project evidence, an exact attributable comparison receipt, and a trusted external release attestation bind the same change axis and Oracle closure.
An external signature proves that its signer endorsed exact digests. It does not prove undeclared behavior, production compatibility, or that the business policy itself is wise.
Lab: split a contaminated upgrade
- Keep one Scenario, Policy, Fixture set, bootstrap, and source-bound verifier. Compare only
baseline-risk.blogewithcandidate-risk.bloge. - Record
changeAxis(),attributable(),equivalent(), reason codes, and the external receipt digest. - Restore the DSL. Freeze the business classpath and compare two different BLOGE toolchain inventories with
blogeVerification(...). - Now change both the risk Operator and BLOGE runtime. Confirm this is not a valid single-axis plan; do not label the observed difference a runtime regression.
- Split the contaminated change into a business-code experiment and a toolchain experiment. Ask the business owner to judge the changed business observation.
- Assess the available governed and comparison evidence. State the highest supported capability and every remaining gap before a release owner signs anything.
Finish with two independent receipts and one gap card, not one green console:
DSL receipt axis · baseline digest · candidate digest · attributable · equivalent
Toolchain receipt axis · runtime digests · business-classpath digest · authority · attributable
Release gap card current capability · missing evidence · owner · next action
Transfer: payment-gateway upgrade attribution
When a payment gateway SDK and retry policy change in the same release branch, a higher success rate cannot be attributed to either one. First freeze business code and compare only SDK inventories; then restore the SDK and compare only the retry policy. Keep separate receipts and let the release owner decide from the two bounded results instead of one contaminated dashboard.
Chapter boundary
- A semantic difference is not automatically an attributable difference.
PROVIDER_ATTESTEDprotocol correctness is not BLOGE-owned execution authority.mvn clean installis build evidence, not Requirement satisfaction.- An attributable comparison alone remains
AUTHORING; release qualification needs governed Project evidence and trusted external attestation. - No comparison in this chapter proves correctness outside the declared Scenario, Oracle, inputs, and runtime boundary.
Experiment acceptance card
- Expected and observed: An upgrade becomes DSL_GRAPH and BLOGE_TOOLCHAIN single-axis receipts.
- Failure and recovery: Change classpath and toolchain together; freeze one axis and compare separately.
- Proof boundary: Proves attribution for fixed inputs, not release readiness.
- Exercise contract: Before/after versions; vary one axis at a time; deliver two receipts; stop when each difference has one candidate cause.
Summary
Freeze everything except one declared axis. Use ScenarioVerifier.compareEvidence(...) for a DSL graph and PairedExecutionCoordinator.compareEvidence(...) for a BLOGE-owned toolchain comparison. Then use the Maven ladder and VerificationClaims to report only the decision capability actually supported. Arc 6 ends where responsible release judgment begins: with evidence that is attributable, bounded, and independently reviewable.
Next: Arc 6 Recap — From Business Promise to Release Evidence.
Coding Agent: Open the versioned task guide.