Releasing Erlang ADK
View SourceThis is the maintainer checklist for preparing, approving, tagging, and
publishing a release. The commands below describe actions to take only after
their prerequisites and approvals are satisfied. This document does not claim
that v0.8.0 has been tagged, pushed, or published.
1. Establish the release candidate
- [ ] Work from the intended release branch and record the candidate commit.
- [ ] Confirm the worktree contains only reviewed release changes.
- [ ] Confirm
src/erlang_adk.app.src, the CLI/doctor output, the README, and`examples/phoenix_adk_ui/mix.exs` all use the intended version. - [ ] Confirm
CHANGELOG.md, the current version contract,`FEATURE_PARITY.md`, `PROVIDER_PROFILES.md`, `README_EXAMPLE_COVERAGE.md`, `TESTING.md`, and `UPGRADING.md` agree with the implementation. - [ ] Preserve both lock files and the Apache-2.0 license.
- [ ] Validate the release's model
provider_profileswith`adk_provider_registry:profiles/0`; review binary aliases, concrete models, endpoint presets/HTTPS hosts, locked options, and credential source descriptors. Do not place a literal production credential in version-controlled configuration. - [ ] Do not include
_build,Mnesia.*, generateddoc, crash dumps,Phoenix `_build`/`deps`, local certificates/keys, provider responses, or secrets.
Useful read-only checks:
git status --short
git diff --check
git diff --stat
git ls-files | grep -E '(^|/)(_build|deps|Mnesia\.|doc/|rebar3\.crashdump)'
find . -type f \
! -path './.git/*' \
! -path './test/fixtures/mcp_test_key.pem' \
-exec grep -E -l \
'(BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY|AIza[0-9A-Za-z_-]{20,})' {} +
The last two commands should produce no release artifact or credential
matches. The excluded PEM is the documented public localhost MCP test key in
test/fixtures; it is not a deployment credential. Review filenames only and
use a dedicated secret scanner if the project's release process provides one.
Test placeholders are allowed; real credentials are not.
2. Use the verified toolchains
- Erlang/OTP 27.3.4.14 (minimum production patch and root pin).
- Elixir 1.17 or newer on OTP 27 (verified: 1.19.5).
- Node.js for Phoenix browser tests (verified: 24.3.0).
- The repository's
./rebar3.
Record exact erl, elixir, mix, and node versions with the release
evidence.
3. Run the core deterministic and package gates
./rebar3 do clean, compile, eunit, ct, dialyzer
./scripts/coverage.sh
./rebar3 xref
./rebar3 eunit --module=readme_examples_test
./rebar3 eunit --module=readme_workflow_examples_test
./rebar3 ct --suite test/runtime/invocations/adk_concurrency_stress_SUITE.erl
./rebar3 ct --suite test/integrations/stress/adk_v05_stress_SUITE.erl
./rebar3 escriptize
_build/default/bin/adk doctor
_build/default/bin/adk config validate examples/agent.json
./rebar3 ex_doc
./rebar3 hex build
./scripts/verify_hex_package.sh
The 1,176 EUnit, six deterministic Common Test, 73.88% coverage, 210-file
Dialyzer, 29 README, four workflow, and 193 focused totals in
TESTING.md are historical v0.7 evidence. The recorded
2026-07-17 v0.8 gate passed 1,414 EUnit tests, six deterministic Common Test
cases, Dialyzer over 235 source modules with no warnings, 74.17% line coverage, 244/244
focused provider/profile/Realtime tests, 30 README plus four workflow tests,
and warning-as-error compilation of all three example modules. Common Test
intentionally skipped 22 paid cases in the deterministic command. Do not
approve a later candidate by copying either release's numbers or by running
only the focused modules.
The seven-module post-audit repair regression set passed 67/67, covering
contiguous in-flight multi-frame priority ordering, Anthropic's minimum
max_tokens value of one, and the 64 KiB synchronous/streaming Gun
header/trailer cap.
The same v0.8 record includes passing xref, escript, doctor 0.8.0, checked configuration validation, ExDoc, Hex 0.8.0 build, and extracted-package compilation verification.
Inspect generated documentation and the Hex tarball/file list. Confirm the package contains core source, public headers, license, README, changelog, the provider-profile/version guides, root examples, and the intentionally packaged Phoenix companion source; it must exclude the test source tree, build/dependency caches, local data, generated Phoenix output, credentials, and crash dumps. The verifier enforces that boundary and also compiles from a clean extracted archive; inspect the generated docs landing page separately.
The root Rebar3 project currently has no rebar3 hex audit gate. Review
rebar.lock and upstream security advisories independently; do not claim that
the Phoenix Mix audit covers it.
4. Run the Phoenix release gate
cd examples/phoenix_adk_ui
mix deps.get
mix assets.setup
mix precommit
MIX_ENV=prod mix assets.deploy
MIX_ENV=prod mix release
mix hex.audit
elixir ../../scripts/verify_phoenix_hex_audit.exs
../../scripts/smoke_phoenix_release.sh proxy 4101
../../scripts/smoke_phoenix_release.sh tls 4443
The 101 ExUnit and 31 browser/audio test totals are historical v0.7 evidence.
The recorded 2026-07-17 v0.8 mix precommit gate passed 103 ExUnit and 40 Node
tests, including negotiated 16/24 kHz voice assertions. Production assets and
release assembly passed, and the assembled release passed both the test-only
trusted-proxy and verified direct-TLS loopback smokes. Each smoke required HTTP
200 from /health and clean shutdown. Follow the exact deployment setup in
the companion README.
mix hex.audit currently returns non-zero for EEF-CVE-2026-43969 and
EEF-CVE-2026-43966 in Cowlib 2.18.0. This is a known release exception, not a
pass. The wrapper must return zero only after matching that exact known set;
any new or missing finding fails so the exception and documentation are
reviewed. Before approval, the release owner must either:
- use an official dependency release that fixes both advisories and rerun the complete gate; or
- explicitly accept the documented temporary exception and its reachability
controls in
SECURITY.md.
Do not use the partial fork patch, remove the audit, or weaken TLS/header validation merely to obtain a zero exit status.
5. Run opt-in provider gates
Use a release-owned test project and export the key in the same shell. These commands use network access, quota, and billable API calls.
export GEMINI_API_KEY="your_api_key_here"
ERLANG_ADK_GEMINI_REST=1 ./rebar3 ct \
--suite test/readme/readme_live_gemini_SUITE.erl
ERLANG_ADK_GEMINI_LIVE=1 ./rebar3 ct \
--suite test/models/gemini/gemini_live_SUITE.erl
The REST suite must use gemini-3.1-flash-lite; the Live suite must use
gemini-3.1-flash-live-preview. Record pass/fail/skip counts and structural
provider reasons without model content or secrets.
The final recorded 0.7 evidence is REST 15/17 with Search and context cache failing on bounded HTTP 429 retries, and Live 5/5. That evidence is historical and does not replace a fresh provider run for a later candidate. A release owner may explicitly accept a provider/quota result, but a skipped or rejected case must never be reported as passing implementation evidence.
The 2026-07-17 v0.8 REST attempt reached Google, but HTTP 401
UNAUTHENTICATED / ACCESS_TOKEN_TYPE_UNSUPPORTED rejected the configured
credential shape. This is external credential evidence, not a pass, skip, or
product regression. No v0.8 paid Gemini Live pass is recorded; deterministic
Live broker/transport coverage must not be described as remote-provider
success.
There is currently no first-party paid Common Test suite for OpenAI Responses, OpenAI Realtime, Anthropic Messages, or an arbitrary compatible endpoint. The release record must describe their deterministic injected-transport/codec evidence accurately and must not infer paid-provider success from configured environment variables. If the release owner runs a manual smoke, record it as separate provider evidence without prompts, outputs, or credentials. Each compatible endpoint is a distinct target, not a blanket certification.
6. Approve the release record
Before creating a tag, record:
- candidate commit and toolchain versions;
- deterministic core, focused, stress, CLI, docs, and package results;
- Phoenix format/compile/test/browser/assets/release/runtime results;
- paid REST and Live model, date, counts, and non-secret failure reasons;
- root dependency review and the exact
mix hex.auditoutput/status; - accepted known limitations, including node locality and partial adapters;
- secret-scan/package-content review; and
- the person or process accepting each security/provider exception.
Do not mark the release approved while version metadata or documentation is stale, a deterministic gate fails, an unexplained test skips, or an advisory has been hidden.
7. Commit, tag, and publish only after approval
Review and commit the release candidate using the repository's normal review process. Verify the commit before tagging:
git status --short
git show --stat --oneline HEAD
Create the immutable tag only when the candidate commit is approved. Prefer a signed tag where maintainer signing is configured; otherwise use an annotated tag and preserve the external approval record:
git tag -s v0.8.0 -m "Erlang ADK 0.8.0"
# or, when signing is unavailable:
git tag -a v0.8.0 -m "Erlang ADK 0.8.0"
Verify the tag points to the approved commit, then push the branch/tag through the repository's protected release process. Publication is a separate credentialed action:
git show --no-patch --decorate v0.8.0
git push origin version_0.8.0
git push origin v0.8.0
./rebar3 hex publish
Do not run these commands from an unreviewed or dirty worktree. Never place a Hex API key, Gemini key, OAuth secret, signing key, or package credential in a command that will be logged.
8. Post-publication verification
- [ ] Verify the Git tag and release notes resolve to the approved commit.
- [ ] Download the published package in a clean environment and compile it on
OTP 27. - [ ] Verify generated API documentation and README/changelog links.
- [ ] Run a minimal deterministic agent/config smoke test from the package.
- [ ] Confirm advisories and accepted limitations are visible in the release
notes. - [ ] Retain the complete release evidence without credentials or model/user
content.
If a package or tag is wrong, do not move an existing public tag or silently replace an immutable package. Publish a corrective version and document the superseded artifact. If credentials or sensitive data escaped, rotate/revoke them immediately and follow the private security process.