Releasing Erlang ADK

View Source

This 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.7.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`, `README_EXAMPLE_COVERAGE.md`, `TESTING.md`, and
    `UPGRADING.md` agree with the implementation.
  • [ ] Preserve both lock files and the Apache-2.0 license.
  • [ ] Do not include _build, Mnesia.*, generated doc, 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

For 0.7.0, compare against the evidence in TESTING.md: 1,176 EUnit tests, six deterministic Common Test cases, 73.88% aggregate Erlang line coverage against the enforced 73% floor, warning-free Dialyzer over 210 files, 29 README tests, four workflow tests, 193 focused v0.7 tests, and both 1,000-operation stress suites.

Inspect generated documentation and the Hex tarball/file list. Confirm the package contains core source, public headers, license, README, changelog, 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

Expected deterministic evidence is 101 ExUnit tests, 31 browser/audio tests, format and warning checks, production assets, and release assembly. Also boot the assembled release on loopback in the test-only trusted-proxy and verified direct-TLS configurations, require HTTP 200 from /health, and stop it cleanly. 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. A release owner may rerun REST with sufficient quota to seek 17/17 or explicitly accept the two quota results. A case that was skipped or rejected by the provider must never be reported as passing implementation evidence.

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.audit output/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.7.0 -m "Erlang ADK 0.7.0"
# or, when signing is unavailable:
git tag -a v0.7.0 -m "Erlang ADK 0.7.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.7.0
git push origin version_0.7.0
git push origin v0.7.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.