0.6.0 — Clarity Is a Runtime Property
Released 2026-09-06 and published to Maven Central as dev.tramai:*:0.6.0, this is TramAI's quality, architecture, and maintainability release. It does not add a new programming model. It makes the existing governed runtime structurally defensible: the execution path is decomposed into named layers, the safety claims are enforced by fail-closed gates instead of convention, the public API is pinned against accidental drift, and every provider and store runs against a shared behavioral contract.
The thesis is the release title. A safety or correctness claim that is not enforced at runtime or in the build is a claim you cannot rely on — so each one was moved into a gate.
What Changed Since 0.5.0
| Area | 0.5.0 | 0.6.0 |
|---|---|---|
| Architecture | Layer boundaries documented | 10 explicit layers enforced by module-boundaries.yml and a single verify060Architecture gate |
| Execution path | Large engine components carried several responsibilities | Invocation, provider, tool, and approval execution decomposed into single-responsibility coordinators |
| Cancellation | Audited per provider | Unconditional preservation enforced by a static verifier across all paths |
| Public API | Stability tiers documented | Kotlin Binary Compatibility Validator (apiCheck) over published modules, plus Kotlin and Java consumer smoke compilation |
| Coverage | Module-level coverage reporting | 100% critical-package branch/instruction ratchet, plus a mutation ratchet over canonical failure modes |
| Outbound safety | Image download constrained by URL checks | OutboundAddressSecurity address-level SSRF defence and bounded response-body reads |
| JDBC errors | Raw SQLException could reach callers | Sanitized mapping with cancellation and domain errors preserved |
| Spring | Separate sovereign starter | One starter, tramai.profile selects standard or sovereign |
| Contracts | Ad-hoc provider and store tests | ProviderTck and *StoreTck behavioral suites enrolled across implementations |
Key Highlights
1. Ten-Layer Architecture and Module Governance
Module topology is explicit rather than emergent. Every Gradle project sits in exactly one of ten layers:
core-contracts, runtime-execution, governance-security, persistence, provider-adapters, framework-integrations, operations-observability, higher-capabilities, applications-examples, testing-support.
config/quality/module-catalog.yml is the authoritative catalogue — every project appears exactly once with its maturity, visibility, owner, dependency policy, and release inclusion, while config/quality/module-boundaries.yml declares the forbidden dependency edges between layers. Both are enforced by verify060Architecture, which also rejects a Gradle project that has no catalogue entry and applies deviation ceilings to the remaining structural hotspots.
The runtime execution path was decomposed as part of this: the invocation handler, invocation execution, provider execution, tool execution, and approval suspension are separate collaborators rather than one component.
2. Static Safety and Cancellation Invariants
Cancellation is a correctness property, not a nicety. CancellationException is preserved and propagated through every provider executor, tool coordinator, and workflow step; if you catch broad exceptions in your own code, use rethrowIfCancellation() from dev.tramai.core.coroutines to rethrow it before handling anything else.
verifyStaticSafetyGuards is a fail-closed gate that rejects, in production code:
- raw coroutine scope creation outside the composition boundary
- unbounded provider response-body reads
- sensitive-payload logging
System.out/System.erroutput
Compiler warnings and dependency hygiene are gated the same way: zero unbaselined compiler warnings and zero unexempted unused direct dependencies across all modules.
3. Binary Compatibility and Consumer Protection
- The Kotlin Binary Compatibility Validator (
apiCheck) tracks API dumps for every publishable module, so an accidental public-signature change fails the build instead of shipping. - Non-public cross-module declarations carry
@ExperimentalTramaiInternalApior@ExperimentalProviderTransportApiand are excluded from the stable freeze. These are internal contracts — referencing them is unsupported. - Kotlin and Java consumer smoke gates compile real external application code against the published artifacts, so a consumer-visible break cannot pass unnoticed.
4. Critical Coverage and Mutation Ratchet
- A 100% critical-package branch and instruction coverage ratchet over the core runtime packages. Coverage cannot regress below the ratchet.
- A mutation ratchet over canonical failure modes, so the failure-path tests are proven to actually detect failure rather than merely execute.
- PIT DEFAULTS analysis runs configuration-cache-compatible, keeping the ratchet practical in CI.
5. Sovereign Runtime and Zero-Egress Hardening
Two independent release-audit findings were remediated in this release:
R12-001— SSRF and local file inclusion in the image downloader.OutboundAddressSecuritynow performs address-level validation: HTTP/HTTPS-only admission, pre-connect DNS resolution, rejection of loopback, link-local, RFC 1918 private, CGNAT, unique-local IPv6, multicast, and any-local addresses, revalidation of every redirect destination, and rejection of URLs carrying user info.R12-002— raw SQL diagnostics leaking from JDBC stores. All JDBC store operations run through a sanitizing wrapper that maps driver failures toIllegalStateExceptionwith redacted detail, while preserving coroutine cancellation and domain exceptions unchanged.
Offline execution is attested and linked to SBOM evidence, so a zero-egress deployment can be proven rather than asserted.
6. Contributor Change Guides and Documentation
Six contributor change guides cover the changes that actually cross module boundaries: adding a provider, adding a workflow step, adding a store, adding an event, adding an approval state, and changing structured-output constraints. Every catalogued module has a module card whose classification links back to the module catalogue, and documentation link integrity is enforced in the build.
Module Detail
tramai-core
Added OutboundAddressSecurity in dev.tramai.core.util: HTTP/HTTPS-only scheme admission, host canonicalization (IDN, bracketed IPv6, alternative IPv4 notations such as octal, hex, and dword), pre-connect address resolution, restricted-address rejection, redirect revalidation, and user-info rejection. Provider response bodies are now read through bounded helpers rather than unbounded reads. The helper is itself @ExperimentalProviderTransportApi — it is a transport-layer contract used by the runtime and providers, not an application API:
// Internal transport usage: fail loud on an oversized provider body.
// The stream is always closed; an over-limit body throws rather than truncating.
val bytes: ByteArray = readBoundedBodyBytes(connection.inputStream, limitBytes = maxBodyBytes)
tramai-engine
The execution pipeline was split into named single-responsibility collaborators — TramaiInvocationHandler, InvocationExecutionCoordinator, ProviderExecutionCoordinator, ApprovalSuspensionCoordinator, and the tool coordinators — each individually testable and gated by the architecture verifier.
Circuit-breaker ownership is now strict and per route, with monotonic generation tracking:
- When an open window expires, exactly one caller is admitted as the HALF_OPEN probe. Other callers keep being rejected until that probe resolves — no stampede.
- A completion carries the admission permit of the generation it belongs to, so a stale completion can no longer close, reopen, or extend a newer breaker generation.
- Admission creates an obligation: the admitted route is wrapped so the permit is always discharged on scope exit, closing the path where a policy or cancellation throw before the route could strand a HALF_OPEN probe.
- Streaming honours
@Operation(providerRetries = n): retryable startup failures retry within the budget, but a failure after the first emitted token is terminal — no retry and no fallback, because visible output destroys recovery authority.
tramai-persistence-jdbc
Every raw database operation in the JDBC stores is now wrapped in withSafeJdbc (JdbcSafeOperation.kt), which sanitizes SQL exceptions and vendor diagnostics to IllegalStateException while preserving CancellationException, TramaiException, and argument-validation failures unchanged. Callers that previously caught java.sql.SQLException must catch IllegalStateException or RuntimeException instead — see Migrating to 0.6.0.
tramai-spring-boot-starter
One canonical starter dev.tramai:tramai-spring-boot-starter composes both runtime integrations — tramai-spring-core for the standard runtime and tramai-spring-sovereign for the sovereign runtime. Runtime selection is explicit and profile-only:
tramai:
profile: standard # or: sovereign
tramai.profile=standard (or absent) yields a Tramai; tramai.profile=sovereign yields a SovereignTramai. The @AiService / @AiTool / constructor-injection programming model is identical under both. The former standalone sovereign starter artifact and its implicit sovereign-default environment post-processor were removed, so sovereign mode can only be chosen deliberately. Wiring for Micrometer, Actuator, OpenTelemetry, and JDBC persistence outboxes is composed automatically.
@AiTool also gained opt-in governance metadata (permission, risk, approval, managedNetworkEgress, audit) with conservative defaults, so a governed tool declares its trust posture at the declaration site. An empty permission preserves the legacy contract — no security metadata is produced, and the sovereign runtime continues to reject such tools.
dependencies {
implementation(platform("dev.tramai:tramai-bom:0.6.0"))
implementation("dev.tramai:tramai-spring-boot-starter") // standard + sovereign
implementation("dev.tramai:tramai-spring-provider-openai") // provider adapter
}
Provider and Store Contracts
Behavioral contracts are now shared rather than re-implemented per adapter:
ProviderTckis the offline compatibility contract for every published provider adapter. The harness pins the expected provider identity and capabilities, so a provider cannot pass by declaring whatever it happens to implement — it must match the roadmap contract.- Store TCKs cover the same shape for persistence:
ApprovalStoreTck,ApprovalContinuationStoreTck,AuditStoreTck,SuspendedInvocationStoreTck,WorkflowCheckpointStoreTck,WorkflowLeaseStoreTck,WorkflowLeaseCheckpointFenceTck,SovereignOpsAuditOutboxStoreTck, andChatMemoryStoreTck. In-memory, file, and JDBC implementations all run the same suites, including replay, stale-version, and concurrent-race cases. - Workflow state machines are covered by dedicated suites for step execution, supervisor recovery, lease coordination, and drain budgets.
If you write your own provider or store, passing the corresponding TCK is what makes it a TramAI implementation in the ordinary sense. That enrollment requirement, and how to satisfy it, is covered in the migration guide.
Quality Gates
0.6.0 is verified through one aggregator rather than a set of remembered commands:
./gradlew verify060MaintainabilityRelease --warning-mode=fail --no-daemon
It composes the release-critical authorities: unit and integration tests, formatting ratchet, Detekt static analysis, static safety guards, compiler warnings, dependency hygiene, cancellation safety, architecture, apiCheck, provider and store TCKs, workflow state machines, Kotlin and Java consumer smoke compilation, the Spring sovereign end-to-end test, sovereign runtime release-candidate verification, zero-egress evidence, publication metadata, local artifact resolution, version alignment, the maintainability baseline, documentation integrity, required release files, and audit closure.
A single command matters here for a specific reason: the same graph that validates a release also validates a pull request, so the gate cannot drift from the thing it claims to check.
Sovereign Runtime Status
The sovereign runtime is a declared release-candidate boundary: governed runtime execution, sovereign routing, DLP, replay-safe approvals, encrypted file-backed persistence, audit and outbox recovery, worker observability, and evidence generation are implemented and locally verifiable.
It is not a stable 1.0 API, and it is not cloud-provider production certification. Key rotation, a production-grade reviewer UI with enterprise IAM, and a production admin REST surface remain deferred.
Migrating from 0.5.0
Five changes need attention in an existing application:
- Replace the old sovereign starter coordinate with
dev.tramai:tramai-spring-boot-starterand select the runtime withtramai.profile. - Move the sovereign allowlists under
tramai.sovereign.*. - Stop catching
java.sql.SQLExceptionfrom JDBC store calls. - Review image URLs fetched by multimodal operations against the outbound address rules.
- Annotated internal APIs are outside the stable promise.
The full walkthrough, with copy-pasteable configuration, is in Migrating to TramAI 0.6.0.
Verifying Your Upgrade
dependencies {
implementation(platform("dev.tramai:tramai-bom:0.6.0"))
}
<dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.tramai</groupId>
<artifactId>tramai-bom</artifactId>
<version>0.6.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Then confirm the two behaviors this release changed:
- A governed tool is still denied when policy denies it, and a JDBC store failure now surfaces as
IllegalStateException. - A suspended approval still resumes exactly once after approval, and not at all after denial.
Publication and Support Boundaries
0.6.0 is published to Maven Central under the dev.tramai group, with signed POMs, module metadata, and binary, sources, and javadoc artifacts for library modules. The BOM aligns the version of every published module.
What this release is not:
- Not a stable 1.0 API. It is a published release-candidate boundary with
apiCheckprotection against accidental drift, not a compatibility promise that no API will change. - Not cloud-provider production certification.
- Not a compliance, regulatory, or security-certification claim. There is no SOC 2, ISO 27001, or EU AI Act conformity claim, and no legal review was performed.
- Not evidence-truth validation — only structural tamper-evidence is verified.
- Not a governed MCP connector, key rotation, or enterprise IAM.
Compatibility Notes
- TramAI 0.6.0 remains a pre-1.0 release line.
- The typed-service, provider, structured-output, orchestration, and observability APIs remain the stable baseline for most consumers.
- Sovereign and security APIs are implemented, documented, and preview-classified; parts of the operational surface remain preview.
- Declarations annotated
@ExperimentalTramaiInternalApior@ExperimentalProviderTransportApiare internal cross-module contracts and are outside the stable compatibility promise. PolicyConfiguration.secure()— deny-by-default — is the secure baseline.PolicyConfiguration.preview()exists only as a 0.4.x migration and testing preset with wildcard allowlists; it is not a production posture.tramai-dashboard,tramai-mcp, andtramai-memory-storeare internal modules in this release and are not published artifacts.- Supported JDK matrix: JDK 21 is the language baseline; CI compiles and runs tests on JDK 25.
