Erlang ADK 0.9.0 release contract
View SourceStatus: released on 2026-08-06. The deterministic release tests recorded below passed. Coverage, Hex/ExDoc packaging, and optional paid-provider runs were not recorded for this release and are not implied by the release status.
Version 0.9 focuses on two connected foundations: a durable, inspectable graph runtime and a broader but still explicit model-adapter fabric. It preserves the 0.8 process ownership, bounded execution, provider-profile, and transport security contracts.
Architectural decisions
- One canonical graph representation.
adk_workflowwithkind => graphis the runtime. The fluentadk_graphbuilder lowers to that representation and can be inspected or run through the workflow engine. - A checkpoint binds to executable meaning. Checkpoint schema v2 records a deterministic definition fingerprint, execution identity, sequence, durable attempts, node status, runnable/waiting work, joins, cycles, and interruptions. Identity is more than workflow ID/version/kind.
- Resume is at least once. A committed result is not replayed. Work whose external effect happened before its result committed may run again. No checkpoint or lifecycle event implies exactly-once external effects.
- Graph data contracts are explicit. Root and per-node JSON Schemas are compiled before execution. State keys may opt into deterministic reducers; the backwards-compatible default remains overwrite.
- Inspection never returns executable configuration. The JSON-safe graph descriptor exposes topology, public policies, schemas, definition identity, and analysis, while omitting callbacks, captured values, tool arguments, credentials, and provider configuration.
- Provider breadth is evidence-based. Native adapters preserve their own wire semantics. OpenAI-compatible local servers use a narrowly scoped loopback exception rather than weakening the general HTTPS and SSRF policy. A configuration recipe or injected transport test is not a blanket model certification.
Implemented 0.9 scope
Durable workflows and continuations
- [x] Emit checkpoint schema v2 with
definition_fingerprint, stableexecution_id, ordered checkpoint lineage, durable attempt records, node/runnable/waiting state, join/cycle state, and interruption metadata. - [x] Accept a valid v1 checkpoint for the 0.8-to-0.9 migration and rewrite it
as v2 at the next commit boundary. A v2 checkpoint with the wrong definition
fingerprint fails as
checkpoint_definition_mismatch. - [x] Add optional
definition_revisionas a non-negative integer or non-empty binary. Anonymous callbacks without it are VM-build-specific and the definition is marked non-portable; applications that resume across code deployment must maintain an explicit revision. - [x] Persist retry attempts. If a process dies while an attempt is marked
running, resume repeats that same one-based attempt number, preserving the
configured
max_attemptsbound and the at-least-once boundary. - [x] Preserve nested pause/resume through sequential, top-level parallel, loop, transfer, graph workflow nodes, and graph-fork workflow branches. Uncommitted siblings cancelled to make a pause durable may run again.
- [x] Allow protected typed-workflow tool nodes to produce a structured
tool_confirmationpause. Approval rechecks the correlated action and runs that exact call; rejection and malformed/mismatched responses fail closed. - [x] Add a separate
lifecycle_receiveroption. It receives ordered, JSON-safe schema-v1 workflow/node/route/fork/join/attempt/retry/checkpoint/ pause/resume/terminal events without changing the legacy event receiver.
Graph execution and data contracts
- [x] Validate graph reachability, terminal visibility, strongly connected components, fork/join topology, shared branches/joins, and typed join targets. Provable unsafe topology is rejected; properties obscured by trusted dynamic callbacks are reported as inspection warnings.
- [x] Add fork completion policies
all,any,first_success, and{quorum, N}. Early policies cancel still-running branches after their condition is met and merge only committed successful branch results.first_successalone tolerates branch failure; the other policies fail fast. - [x] Compile optional
input_schemaandoutput_schemaon every graph node, validate node input before its action, and validate node output before its delta becomes visible. - [x] Add workflow
state_reducersfor binary state keys:overwrite,append,sum, andreject_conflict(withreject_conflictsaccepted as an alias). Reducer type/conflict failures identify only the key and policy, not the state values. - [x] Add deterministic, JSON-safe graph description and DOT/Mermaid rendering
through
erlang_adk:inspect_graph/1,erlang_adk:render_graph/2, and the correspondingadk_graphfunctions. - [x] Add local factory commands
adk graph validate MODULE FUNCTION,adk graph describe MODULE FUNCTION, andadk graph render MODULE FUNCTION --format mermaid|dot|json. Factory lookup is restricted to already available modules and exported zero-arity functions; command input does not create arbitrary atoms or select runtime modules.
Model adapters and provider profiles
- [x] Route agent feature checks through adapter capability declarations and advertise provider-neutral generation configuration only where implemented.
- [x] Constrain profile-selected Live capabilities to the selected adapter's ceiling and derive trusted audio input rates from the resolved capabilities.
- [x] Add an explicit keyless local endpoint policy for
adk_llm_compatible. It is limited to numeric127.0.0.1or::1, authnone, and non-Live requests; the general custom-origin HTTPS/private-address protections are unchanged. - [x] Add native Vertex AI publisher-model GenerateContent/SSE support with fixed Google authority/path derivation, Gemini-compatible content/tool encoding, OAuth bearer handling, structured output, and bounded streaming.
- [x] Add trusted Vertex OAuth sources for an explicit access token or
google_adc. A profile-selectedgoogle_adcsource uses only the fixed, boundedgcloud auth application-default print-access-token --quietinvocation. A trusted direct configuration may instead inject anadc_token_provider; profile callers cannot. No caller-selected executable, arguments, URL, or headers cross that boundary. - [x] Document implementation and evidence tiers for Gemini/Gemma, OpenAI, Claude, Vertex, Ollama, vLLM, LiteLLM Proxy, and transparent HTTPS gateways. This is not a claim that every model exposed by those products is supported.
Compatibility and migration
- Existing workflows without
state_reducersretain last-write/overwrite state-delta behavior. - Existing root schemas continue to work; per-node schemas are optional.
- Existing fork nodes default to
join_policy => all. - Existing v1 checkpoints can be resumed only against a matching ID/version/kind and become definition-bound v2 checkpoints at the next boundary. After that rewrite, reverting to 0.8 is not a supported resume path.
- Durable applications should add and maintain
definition_revisionbefore a rolling code deployment. Changing the revision intentionally invalidates old v2 checkpoints. lifecycle_receiveris opt-in and separate fromevent_receiver.
See UPGRADING.md,
DURABLE_INVOCATIONS.md, and
GRAPH_WORKFLOWS.md for operational details.
Explicit limitations
- The runtime provides at-least-once recovery, not exactly-once actions, branches, tool calls, lifecycle delivery, or external side effects.
- The graph runtime executes the declared node/fork/nested-workflow model; it is not a general arbitrary multi-node branch-region scheduler.
- There is no drag-and-drop visual editor or upstream Agent Config code generator. The release adds read-only description and text rendering.
- There is no automatic cross-provider cost/latency router, fleet model discovery, or guarantee covering 100+ model names. Applications select a trusted adapter/profile and validate their exact endpoint.
- Upstream Agent Skills are not implemented or inferred from ordinary prompts, files, MCP resources, or Erlang modules.
- Vertex paid-provider success, arbitrary compatible-server behavior, and the final complete release gates are not implied by deterministic fixtures.
- The Vertex slice does not implement partner publishers, endpoint resources, custom origins, Live, thinking/built-in tools, or context caching.
- Local endpoints are loopback-only and development-oriented. Private LAN, container bridge, remote, or hostname-based cleartext endpoints remain rejected; use a trusted HTTPS gateway for those deployments.
Release evidence ledger
The commands and interpretation rules are in TESTING.md.
Populate this ledger only from one reviewed release revision.
| Gate | 0.9 release result |
|---|---|
| Clean compile, EUnit, Common Test, Dialyzer | Passed: 242 production and 271 test modules compiled with -Werror; all 1,495 EUnit tests and all 6 Common Test cases passed; a fresh Dialyzer run reported 0 warnings |
| Deterministic line coverage | Not recorded for this release; the existing floor was not lowered or reinterpreted |
| Focused graph/workflow/model/provider/CLI tests | Passed within the 1,495-test aggregate run |
| Xref, escript, doctor, config validation | ./rebar3 xref passed with 0 undefined or deprecated calls or functions; release-contract and CLI tests passed. A complete escript/doctor release execution was not recorded. |
| ExDoc, Hex build, extracted-package compile | Not recorded for this release |
| Phoenix gates | Passed: locked dependencies; warnings-as-errors compilation; 103 ExUnit and 40 browser/audio tests; production assets and release assembly; trusted-proxy and verified direct-TLS health smokes; exact documented advisory-exception verifier |
| Phoenix dependency audit | Bandit 1.12.4, Cowboy 2.18.0, and Cowlib 2.19.0 remove EEF-CVE-2026-65623, EEF-CVE-2026-65624, and EEF-CVE-2026-59248. Raw mix hex.audit remains non-zero for three package findings covering EEF-CVE-2026-43969 and EEF-CVE-2026-43966; the exact package/advisory verifier passed. |
| Paid Gemini/Vertex/OpenAI/Anthropic/compatible evidence | No new 0.9 remote-provider result recorded here |