TramAI - governed AI workflows for Java and Kotlin

Quality Gates

TramAI 0.6.0 is the release where the quality story stopped being a set of good intentions and became an executable contract. This page is for contributors: it lists what the gates are, what each one refuses to let through, and how to run them.

Every gate name on this page is a real Gradle task or a real config file in the repository. If a name is not here, it does not exist.

The Authoritative Command

./gradlew verify060MaintainabilityRelease --warning-mode=fail --no-daemon

This is the release verification entry point. It is a fail-closed aggregator: it depends on the full authority list below, and its doLast refuses to pass if any required authority task was not actually scheduled in the graph, or if the publishable module set comes out empty. It is deliberately not part of the normal check lifecycle — everyday development uses check and verifyPr; release verification is invoked explicitly.

DomainAuthorities
Lifecycle and testscheck, all subproject test tasks
Formatting and analysisspotlessCheck, verifyStaticAnalysis, verifyStaticSafetyGuards, verifyCompilerWarnings, verifyDependencyHygiene, verifyCancellationSafety
Architecture and contractsverify060Architecture, verifyMaintainabilityBaseline, verifyModuleManifest, verifyModuleMatrixDrift, apiCheck
Coverage and mutationverifyCriticalCoverage, verifyReleaseMutation
Test integrityverifyJUnitTestSignatures, verifyChangePolicy
ConsumersKotlin and Java consumer smoke compile tasks, :examples:spring-sovereign-starter:e2eTest
PublicationverifyPublicationMetadata, verifyPublishedLocalArtifacts, verifyVersionAlignment
Sovereign runtimeverifySovereignRuntimeReleaseCandidate, verifySovereignRuntimeVerificationRepoClosure, verifySovereignRuntimeConsumerSmoke, verifySovereignDocumentIntelligenceEvidenceRun, verifySovereignRuntimeApiBoundary, verifySovereignRuntimeClosureDocs, verifySovereignOpsObservabilityDocs, verifySovereignEvidencePackContainsReleaseBundle, prepareSovereignReleaseArtifacts, verifySovereignReleaseManifest
Documentation and auditverifyReleaseDocumentationIntegrity, verifyReleaseRequiredFiles, verifyAuditClosure
Offline proofverify060ZeroEgress
Build logicthe build-logic included-build test suite

The Day-To-Day Gates

./gradlew verifyPr is the primary local gate. It aggregates the maintainability baseline, change policy, module manifest, module matrix drift, critical coverage, the mutation ratchet, the module documentation contract, and the build-logic test suite. The root build script wires the six code-quality authorities into both check and verifyPr.

GateAuthority fileInvariant
spotlessCheckroot .editorconfig + a pinned KtLint engineEvery Kotlin file changed relative to the formatting base satisfies one deterministic formatting policy. The gate is ratcheted (-PtramaiFormattingBaseRef=<sha> in CI), so untouched legacy source is never mass-reformatted.
verifyStaticAnalysisconfig/detekt/detekt.yml, config/detekt/baseline.xmlOne repository-wide Detekt run (pinned 1.23.8). The baseline is a ceiling, not an allowance: removals are allowed, additions fail unless the change is an explicit baseline migration.
verifyCompilerWarningsconfig/warnings/baseline.jsonZero unbaselined compiler warnings. Warning identity is path plus Kotlin internal diagnostic name plus a normalized message fingerprint — line and column are excluded so moving code does not manufacture a new finding.
verifyDependencyHygieneconfig/dependency-hygiene/exemptions.ymlNo unused direct main-scope dependency. Exemptions are module + configuration + coordinate + rationale; a stale exemption fails.
verifyStaticSafetyGuardsconfig/quality/static-safety-guards.ymlFour production-code bans: raw lifecycle creation (GlobalScope, Thread, Executors.new*, CoroutineScope, SupervisorJob, addShutdownHook), unbounded HTTP body reads, sensitive-payload logging, and System.out/System.err. Exemptions are per rule + path + symbol + occurrence count, and the count is ratcheted: a new same-symbol occurrence in an approved file fails, and a removal below the declared count is stale and also fails.
verifyCancellationSafetybase-aware comparisonCancellationException is preserved and propagated on every path; no new broad catch that swallows or wraps it.
verifyJUnitTestSignatures—Guards against JUnit Jupiter silently discarding a test whose JVM return type is not void.
verifyChangePolicychange classificationRejects change mixes that should not ship together (for example production code plus its governing analyzer, or an unbounded deviation increase).
verifyModuleManifestconfig/quality/module-catalog.ymlSettings ↔ catalog exact-set equality, valid classification combinations, BOM and publishing derivation consistency.
verifyModuleMatrixDriftdocs/reference/module-matrix.mdThe generated module matrix matches a fresh generation from the catalog.
verifyModuleDocContractdocs/modules/Every module in the catalog has a card.
verifyMaintainabilityBaselineconfig/quality/0.6.0-baseline.json, config/quality/maintainability-deviations.ymlSource metrics, resolved dependencies, cancellation catches, global state, nondeterminism sources, and the runtime protocol catalog stay inside the committed baseline and its declared deviation ceilings. verifyRuntimeNondeterminism is part of this authority.

Baselines are the mechanism that lets a large, evolving repository be honest instead of aspirational. The rule that makes them meaningful is that debt may only shrink: a green gate means zero new findings, not zero findings.

A deliberate, documented exception

verifyCompilerWarnings verifies modules only. build-logic's own warnings are frozen in the inventory but not gated, because kotlin-dsl compilation cannot be reproduced by a standalone kotlinc and root listeners cannot capture included-build compiler output. That gap is documented in the epic rather than papered over.

Architecture and API Gates

./gradlew verify060Architecture

The architecture gate runs ten checks — module-manifest, publishing-topology, dependency-boundaries, dependency-cycles, global-state, api-architecture, protocol-catalog, cancellation-safety, provider-contracts, store-contracts — and writes build/reports/tramai/architecture/architecture-report.json before it throws, so a failing run still leaves typed evidence. Two consecutive runs must produce a byte-identical report. See Module Architecture for the layer rules it enforces.

apiCheck is the binary-compatibility authority: the committed api/<module>.api dumps must match both the current source and the stability policy for that module. The Kotlin and Java consumer smoke compile tasks feed the same api-architecture check. See API and Binary Compatibility.

Critical Coverage and Mutation Ratchets

Coverage and mutation policy are declared in config/quality/test-quality.yml and measured into config/quality/coverage-baseline.json.

Coverage. Nine critical modules participate — :tramai-core, :tramai-engine, :tramai-security, :tramai-sovereign, :tramai-standalone, :tramai-structured, :tramai-orchestration, :tramai-persistence-file, :tramai-persistence-jdbc — with a 1.0 percentage-point regression tolerance and one declared exclusion (**/model/**, generated model classes). There is deliberately no percentage floor: the ratchet is the policy, and the measurement is base-authoritative — the policy and baseline that judge a pull request are read from the pull request's base, never from the candidate. The 0.6.0 release notes summarise this as a "100% critical branch/instruction coverage ratchet on core runtime packages"; the numbers that actually exist live in the coverage baseline, so read those rather than the summary.

Mutation. The committed mutation baseline records the measured population for seven families — policy, approval, routing, retry, tools, evidence, structuredOutput — with a v2 identity schema (module, class, method descriptor, index, mutator, description, block; line numbers excluded so moving code does not churn the ratchet). Mutants are reduced to a canonical KILLED / NON_KILLED outcome in the ratchet, while the raw PIT status is kept for diagnosis. MutationRatchetVerifier then enforces an exact-set comparison against the base authority:

  • a previously killed identity that becomes non-killed fails;
  • a new non-killed identity fails;
  • a survivor is only tolerated when config/quality/mutation-classifications.yml carries an exact-identity classification (equivalent-mutant or tool-limitation) with a reason;
  • narrowing the configured families, modules, target classes, or target tests fails;
  • drift in the PIT plugin version, engine version, mutator set, or timeout configuration fails.

Two distinct modes matter operationally. On a pull request, verifyMutationRatchet runs no PITest campaign — it is a pure in-memory comparison of committed files against the base, fully deterministic and cheap. The real PITest campaign is generateCriticalMutationBaseline, a human-supervised measurement ceremony run during enrollment or audit, never in pull request CI.

Documentation Gates

Documentation is gated like code. verifyReleaseDocumentationIntegrity checks relative links and rejects hardcoded developer paths in release docs; verifyReleaseRequiredFiles requires the release artifacts (changelog, release notes, migration guide, readiness document) to exist; verifyAuditClosure requires every P0/P1 audit finding to be closed and every deferred finding to retain an owner and rationale. Contributor change guides live under docs/architecture/change-guides/ and are expected to be updated in the same change that moves the contract they describe.

When a Gate Is Red

The repository's protocol is diagnosis before editing:

  1. Read the failing step and its full log; inspect the artifact if there is one.
  2. Classify the failure — production defect, test defect, analyzer defect, baseline mismatch, environment mismatch, workflow defect, or transient external failure.
  3. Do not modify a gate until the evidence shows the gate is wrong, and do not raise a deviation ceiling to make a red build green.
  4. Stop and report after two unsuccessful fixes instead of applying a third speculative patch.

apiCheck and verify060Architecture are not wired into check; run them explicitly (or run the release command) when your change touches the public surface or the module graph.