6.5 KiB
JPA Evidence Gradle Model Decoupling Design
Context
GenerateJpaEvidenceManifestsTask currently performs evidence generation after its producer tasks run. Its semantic contract is useful, but the task action reaches back into the live Gradle model through getProject(), resolves configurations, locates Task instances, reads Test report locations, inspects TaskState, and reads root extra properties.
Gradle 9 deprecates Task.project access at execution time and Gradle 10 will reject it. More importantly, the current task mixes two responsibilities:
- Gradle configuration/model discovery.
- Pure evidence assembly from producer results.
The refactor must separate those concerns without weakening evidence claims.
Goals
- Preserve the current readiness-card and evidence-manifest semantics.
- Remove execution-time
Project,Task, andTaskStateaccess fromGenerateJpaEvidenceManifestsTask. - Preserve JUnit XML as the source of truth for test execution evidence.
- Preserve successful non-Test task execution as the source of truth for
task-claimssuch as architecture/configuration claims. - Represent generator inputs with typed Gradle properties rather than hidden project lookups.
- Keep producer task names and readiness-card schema unchanged.
- Remain compatible with
--warning-mode=failon Gradle 9 and prepare the evidence lane for Gradle 10.
Non-goals
- Do not redesign the readiness-card schema.
- Do not change evidence grades, prerequisite semantics, content hashing, R1/R2 rules, or output layout.
- Do not introduce marker files into every producer task.
- Do not move release orchestration into the persistence-JPA leaf.
- Do not add new runtime dependencies to application modules.
Architecture
1. Build service owns task completion outcomes
Introduce JpaEvidenceExecutionService, a Gradle shared build service implementing OperationCompletionListener.
The plugin registers it through BuildEventsListenerRegistry.onTaskCompletion(...) so the service receives TaskFinishEvent events without the generator querying TaskState.
The service stores a thread-safe typed outcome for each task path:
Task path
-> SUCCESS
-> FAILED
-> SKIPPED
Only SUCCESS satisfies an evidence task-claim. Failed or skipped producers do not cover the claim.
The service is build-scoped and contains no Project reference.
2. Test evidence remains file-based
JUnit evidence already has a durable output: Gradle's JUnit XML result directory. The plugin resolves every readiness/support Test task during configuration and supplies a typed mapping:
absolute task path -> JUnit XML result directory
The generator reads those directories directly with JUnitEvidenceReader; it never locates a Test object.
Non-Test support tasks continue to participate in the task graph but do not produce JUnit evidence.
3. Configuration-derived values become task inputs
The plugin supplies these inputs before execution:
- evidence profile
- CI job
- artifact location
- topology
- PostgreSQL image
- source revision
- traceable version
- resolved PostgreSQL JDBC version
- resolved Hibernate ORM version
- resolved Flyway version
- repository-relative evidence output location used by the candidate default
- JUnit result-directory mapping
The generator reads only its properties/files plus the execution service.
releaseProvenance is the preferred source for revision/version. The existing extra-property compatibility bridge is no longer read by the generator.
4. Dependency-version discovery stays in plugin configuration
The JPA evidence plugin owns the Gradle Configuration object. It derives the three relevant resolved module versions and writes them into typed task properties before the generator executes.
This keeps dependency-graph access out of the task action. The existing coordinates remain unchanged:
org.postgresql:postgresqlorg.hibernate.orm:hibernate-coreorg.flywaydb:flyway-core
5. Generator becomes an evidence assembler
The generator task action may use:
- its declared Gradle properties/files
ExecOperationsfor git/docker commands already owned by the taskFileSystemOperationsJpaEvidenceExecutionService- pure parser/verifier/helper classes
It must not call:
getProject()
Project.findProject(...)
Task.getState()
TaskContainer.findByName(...)
ConfigurationContainer.getByName(...)
ExtraPropertiesExtension.get(...)
6. Evidence semantics
For a readiness card:
evidence.scenariosare covered only by selectors found in JUnit XML.evidence.task-claimsare covered only when the build service reports the named task completed successfully in the current build.no-skipremains based on JUnit result counts.- prerequisite manifest ordering and hashing remain unchanged.
- candidate/R2 blockers remain unchanged.
The primary foundation card still obtains architecture/configuration coverage from successful execution of its declared producer tasks; the mechanism changes from TaskState lookup to task-finish events, not the meaning.
Error handling
- A readiness task expected to produce JUnit evidence but missing from the configured result mapping is a hard failure.
- A configured JUnit result directory that contains no usable result remains subject to the existing JUnit evidence validation.
- A task claim with no successful completion event is simply uncovered and therefore becomes missing required evidence when that claim is required.
- Unsupported evidence profile remains a hard failure.
- Missing immutable image digest/dependency versions retain the existing blocker behavior.
Testing
- Unit-test task-event classification in
JpaEvidenceExecutionService. - Unit-test pure JUnit result lookup from configured task-path/directory inputs.
- TestKit: apply
ca.jpa-evidencein a fixture and verify the generator task exposes typed inputs without execution-time project lookup. - Existing JPA evidence verifier tests must remain green.
- Run
build-tools:check --warning-mode=fail. - Run
verifyJpaReadinessRegistry verifyJpaReleaseGateTasks --warning-mode=fail. - Run the affected JPA leaf
check. - Run a candidate evidence lane far enough to confirm no
Task.projectdeprecation is emitted; environment-dependent Docker/Testcontainers failure may be reported separately from Gradle-model warnings.
Migration boundary
This change only decouples evidence generation from the live Gradle model. It does not alter the readiness registry, producer tasks, JUnit test suites, manifest schema, release workflow, or evidence verification policy.