What happens
The runtime-e2e legs and the heartbeat workflow build with package and no clean, then pick the SDK jar with a glob: SDK_JAR=$(ls target/axonflow-sdk-*.jar | grep -v sources | grep -v javadoc | head -1), or a looser variant. Any jar already in target/ that survives the filter and sorts first is used, and nothing flags it:
- an older-version jar:
axonflow-sdk-9.2.0.jar sorts before axonflow-sdk-9.3.0.jar;
- where the filter omits
javadoc, the javadoc jar: axonflow-sdk-9.3.0-javadoc.jar sorts before axonflow-sdk-9.3.0.jar, because - (0x2d) sorts before . (0x2e).
The leg then runs against a build that is not the tree it claims to prove.
Measured instance
Replicating heartbeat-real-stack.yml's Linux step locally (sdk-java main 2ad7091d2, and a PR branch on it) after an mvn install had left axonflow-sdk-9.3.0-javadoc.jar in target/: the step's ls target/axonflow-sdk-*.jar | grep -v sources | head -1 picked the javadoc jar, and javac failed on tests/heartbeat-real-stack/SmokeJava.java:16 with package com.getaxonflow.sdk does not exist. The same step from an empty target/ passes at main and at the branch, and planting the javadoc jar reproduces the failure. CI's fresh checkout, built with -Dmaven.javadoc.skip=true, never has that jar, so CI is not affected today; a local run of any of these is.
Where the pattern is (sdk-java main 2ad7091d2)
Executed:
.github/workflows/heartbeat-real-stack.yml:75 (no javadoc filter)
runtime-e2e/pep_handshake_planes/run.sh:16
runtime-e2e/read_path_identity/run.sh:14
runtime-e2e/typed_policies/run.sh:15
runtime-e2e/v11_decision_provenance/run.sh:14
Documented as the run recipe, copied by whoever runs the leg (23 more), four of them with a bare | head -1 and no filter at all: runtime-e2e/README.md:72, runtime-e2e/decision_context_transfer_basis/DecisionContextTransferBasisTest.java:18, runtime-e2e/x-axonflow-client/README.md:45, runtime-e2e/x-axonflow-client/SdkClientHeaderTest.java:12. The others sit in the READMEs and class Javadoc of async_verdict_parity, audit_model_real_wire, authzen_evaluation, caller_name_audit, decide_fulfill_obligation, decision_context_transfer_basis, error_classification_403, masfeat_registry_summary, mcp_server_tool_split, trustmanager_prod_guard and x_axonflow_client.
Proposal
A shared runtime-e2e/lib/sdk-classpath.sh that every run.sh sources instead of repeating its build prelude (four copies with the slf4j-simple block today: pep_handshake_planes, read_path_identity, typed_policies, v11_decision_provenance):
- build once, then name the jar by the pom's version (
target/axonflow-sdk-${version}.jar, the version from mvn -q -DforceStdout help:evaluate -Dexpression=project.version) and fail when it is absent, instead of globbing;
- write the dependency classpath and add the
slf4j-simple binding;
- keep the comment that
-DskipTests alone still runs the unit suite in this pom (skipUnitTests).
The recipes in the READMEs and class Javadoc then point at run.sh, and the heartbeat step names the jar the same way.
Refs getaxonflow/axonflow-enterprise#3746
What happens
The runtime-e2e legs and the heartbeat workflow build with
packageand noclean, then pick the SDK jar with a glob:SDK_JAR=$(ls target/axonflow-sdk-*.jar | grep -v sources | grep -v javadoc | head -1), or a looser variant. Any jar already intarget/that survives the filter and sorts first is used, and nothing flags it:axonflow-sdk-9.2.0.jarsorts beforeaxonflow-sdk-9.3.0.jar;javadoc, the javadoc jar:axonflow-sdk-9.3.0-javadoc.jarsorts beforeaxonflow-sdk-9.3.0.jar, because-(0x2d) sorts before.(0x2e).The leg then runs against a build that is not the tree it claims to prove.
Measured instance
Replicating
heartbeat-real-stack.yml's Linux step locally (sdk-java main2ad7091d2, and a PR branch on it) after anmvn installhad leftaxonflow-sdk-9.3.0-javadoc.jarintarget/: the step'sls target/axonflow-sdk-*.jar | grep -v sources | head -1picked the javadoc jar, andjavacfailed ontests/heartbeat-real-stack/SmokeJava.java:16withpackage com.getaxonflow.sdk does not exist. The same step from an emptytarget/passes at main and at the branch, and planting the javadoc jar reproduces the failure. CI's fresh checkout, built with-Dmaven.javadoc.skip=true, never has that jar, so CI is not affected today; a local run of any of these is.Where the pattern is (sdk-java main
2ad7091d2)Executed:
.github/workflows/heartbeat-real-stack.yml:75(nojavadocfilter)runtime-e2e/pep_handshake_planes/run.sh:16runtime-e2e/read_path_identity/run.sh:14runtime-e2e/typed_policies/run.sh:15runtime-e2e/v11_decision_provenance/run.sh:14Documented as the run recipe, copied by whoever runs the leg (23 more), four of them with a bare
| head -1and no filter at all:runtime-e2e/README.md:72,runtime-e2e/decision_context_transfer_basis/DecisionContextTransferBasisTest.java:18,runtime-e2e/x-axonflow-client/README.md:45,runtime-e2e/x-axonflow-client/SdkClientHeaderTest.java:12. The others sit in the READMEs and class Javadoc ofasync_verdict_parity,audit_model_real_wire,authzen_evaluation,caller_name_audit,decide_fulfill_obligation,decision_context_transfer_basis,error_classification_403,masfeat_registry_summary,mcp_server_tool_split,trustmanager_prod_guardandx_axonflow_client.Proposal
A shared
runtime-e2e/lib/sdk-classpath.shthat everyrun.shsources instead of repeating its build prelude (four copies with theslf4j-simpleblock today:pep_handshake_planes,read_path_identity,typed_policies,v11_decision_provenance):target/axonflow-sdk-${version}.jar, the version frommvn -q -DforceStdout help:evaluate -Dexpression=project.version) and fail when it is absent, instead of globbing;slf4j-simplebinding;-DskipTestsalone still runs the unit suite in this pom (skipUnitTests).The recipes in the READMEs and class Javadoc then point at
run.sh, and the heartbeat step names the jar the same way.Refs getaxonflow/axonflow-enterprise#3746