Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Added

- **Explicit runtime lifecycle ownership (PR #226).** `Tramai` and `SovereignTramai` are now `AutoCloseable` and own exactly one lazily-created runtime (one engine) shared by every `create()`/`runtime()` call — previously every `create()` leaked an unreachable engine. Closing is idempotent and concurrency-safe; after close, `create()`/`runtime()` and old proxies fail fast with a fixed `IllegalStateException` before any provider work. `TramaiEngine.close()` cancels once and awaits engine-hierarchy termination (self-close safe), and terminates in-flight suspend invocations; the caller continuation is always resumed exactly once. Spring closes the shared runtime via `destroyMethod = "close"`, so multiple `@AiService` beans share one owned engine. TramAI closes only resources it creates; externally supplied providers/stores/clients/observers remain caller-owned. API surface addition is additive: `Tramai`/`SovereignTramai` gain `close()`; all constructor descriptors remain byte-identical to 0.5.0 (note: adding the `AutoCloseable` supertype is source-compatible but affects compiled negative-`instanceof` checks). Epic 1.3 Runtime Lifecycle Ownership is complete.

- **Safe persistence failure boundaries (PR #225).** Persistence stores expose fixed, cause-free failure text; raw paths, SQL, and payloads flow only to `PersistenceFailureDiagnosticObserver`; worker observers receive safe failures; existing exception and store ABI is preserved by the binary fixture. Epic 1.2 Safe Error Boundaries is complete.

- **Safe provider and built-in workflow-step failure boundaries (PRs #222, #223).** Provider HTTP rejections and built-in HTTP, shell, MCP, Codex, and Hermes workflow failures expose fixed cause-free public exceptions with typed failure codes. Original failure detail is retained only by an explicitly configured, fail-open diagnostic observer; public workflow events omit URLs, commands, raw tool names, and failure reasons. Existing public exception constructor descriptors remain compatible with 0.5.0 clients.
Expand Down
12 changes: 12 additions & 0 deletions docs/ROADMAP-0.6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ This phase is intentionally completed before large decomposition work.

**Goal:** Ensure no convenience API creates an uncloseable runtime.

> **Status:** ✅ Complete — PR #226. `Tramai`/`SovereignTramai` are `AutoCloseable` and own one runtime/engine; `close()` cancels and joins engine-owned work (blocking calls, suspend invocations, streaming collections) via an internal lifecycle job; caller-supplied `job`/`scope` are never cancelled/joined; Spring closes via `destroyMethod`; resource ownership documented.

### Tasks

1. Make `Tramai` own one engine or one runtime session rather than constructing an unreachable engine per `create()` call.
Expand All @@ -373,6 +375,16 @@ This phase is intentionally completed before large decomposition work.
- Repeated creation does not accidentally create independent hidden engines.
- Spring context shutdown leaves no TramAI-owned jobs or hooks active.

### Leak-test evidence matrix (roadmap task 6)

| Requirement | Existing proof |
|---|---|
| Engine jobs | PR #226 lifecycle tests: `close() cancels and joins` blocking/suspend/streaming engine-owned work (`blocking invocation in long suspension is cancelled and joined by close`, `self close from owned coroutine does not deadlock`, `self close from streaming owned coroutine does not deadlock`, `stream start racing close never hangs the collector`, `close does not deadlock when caller supplied its own job and scope`) |
| Worker jobs | Existing worker shutdown/cancellation tests in tramai-orchestration (`TramaiWorkerTest`, lease-drain and shutdown coverage from Epics 1.1/1.2) |
| Subprocesses | PR #216/#221 cancellation contract (`SubprocessCancellationContractTest` in tramai-orchestration) |
| HTTP response streams | Provider-level InputStream cleanup tests in tramai-openai `OpenAiProviderTest`: `stream closes response body after done marker`, `stream closes response body after malformed chunk`, `stream closes response body when collector stops after first token`, `mid stream io failure is retryable sanitized and observed`; plus #226 engine streaming lifecycle tests (`streaming collection suspended indefinitely is cancelled and cleaned up by close`, `mid-collection close terminates an in-flight stream`) and the springboot example E2E smoke test |
| Shutdown hooks | `TramaiWorkerTest`: `close deregisters the JVM shutdown hook and retains no reference` — proves the registered hook is absent from `Runtime` after close (`removeShutdownHook` returns false) and the worker retains no `Thread` reference; plus Spring `destroyMethod` close + context-shutdown tests and `repeated close is harmless` idempotency test in tramai-standalone |

---

## Epic 1.4: HTTP network-boundary correctness
Expand Down
2 changes: 1 addition & 1 deletion docs/modules/tramai-engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ The test suite covers **28 behavioral scenarios** across 2 test files:
|------|------|-------------|
| `TramaiEngine` | Class | Main engine: creates AI-backed proxies from annotated interfaces |
| `TramaiEngine.create()` | Method | Returns a JVM proxy implementing the given service type |
| `TramaiEngine.close()` | Method | Cancels the engine's coroutine job hierarchy |
| `TramaiEngine.close()` | Method | Cancels and joins all engine-owned work: blocking calls, suspend invocations, and streaming collections. The caller-supplied `job`/`scope` constructor parameters are never cancelled or joined |
| `RetryPolicySettings` | Data class | Retry delay computation: max `Retry-After` cap, jitter ratio |
| `CircuitBreakerSettings` | Data class | Per-provider circuit breaker: enabled, threshold, open duration |
| `TokenBudgetSettings` | Data class | Token budgets: hard per-attempt, hard/soft per-operation |
Expand Down
Loading
Loading