Skip to content

Release v0.22.0 - #681

Merged
samrusani merged 5 commits into
mainfrom
release/v0.22.0
Oct 26, 2026
Merged

samrusani merged 5 commits into
mainfrom
release/v0.22.0

Conversation

@samrusani

@samrusani samrusani commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Summary

Release prep for v0.22.0, a minor release on v0.21.1. It moves every version site to 0.22.0, dates the eight changelog entries that sit under Unreleased, adds the notes in their pending state and records the release candidate in the control documents. v0.21.1 stays the latest published release, and nothing here tags, publishes or dispatches anything.

What v0.22.0 contains (git log --first-parent v0.21.1..origin/main, merged at 912bcff5):

24 files under apps/api/src differ from v0.21.1. The behaviour changes among them are #680, #671 and #673. No tool is added (default 3, full 12, legacy 74 and 77), no migration is added (apps/api/alembic is byte for byte the folder of the tag, PostgreSQL stays at 20261011_0097), and the only new CLI flags are --sources and --drop of alice-memory reindex-embeddings. There are five new settings and one new value of ALICE_SEARCH_QUALITY.

What moved

  • Version 0.22.0 at the six sites scripts/release_check.py requires: pyproject.toml, apps/web/package.json, packaging/mcpb/manifest.json, plugins/alice-memory/.claude-plugin/plugin.json, and the two command pins in plugins/alice-memory/.mcp.json and plugins/alice-memory/hooks/hooks.json. Every other 0.21.1 stays, because it names the latest published release, the baseline, the checksums or the marketplace pin (ref v0.21.1 and its commit 8d0bac27).
  • CHANGELOG. The seven Unreleased (on main, not in v0.21.1): entries lose the prefix and the eighth is already without it; all eight move under the dated v0.22.0 heading (2026-10-26, in the form release_check.py requires), and an empty ## Unreleased is above it. Two wording edits beyond the prefix: the embeddings entry said "Nothing reads the vectors yet", which the next entry contradicts, so it now says nothing reads them unless ALICE_SEARCH_QUALITY=vectors is set (run: on a vault that holds vectors, with the opt-in on and the endpoint set, a recall without that value returns the same bytes as v0.21.1 and makes the same one request, the memory query); and one noun in the braces entry, in two places, is changed to meet the wording rule for this repository.
  • Three documents carried the marker without the word Unreleased. docs/alpha/mcp-tools.md, docs/benchmarks/showcase/harness.md and docs/benchmarks/showcase/what-changed-and-why.md said "On main, not in v0.21.1". They say "From v0.22.0" now, as Release v0.21.0 #660 did for v0.21.0. The marker test of v0.21.1 only matched the form with "Unreleased"; the new test matches both.
  • Notes. docs/release/v0.22.0-release-notes.md, 14.4 KB, state pending and pending, no checksums file. Sections: What to do after upgrading, The agent output route, Passage vectors (an opt-in), Other changes in the package, Behaviour changes an integrator will notice, Security, What this release does not claim, Install. The Security section opens with the same two sentences as the v0.21.1 notes and ends its first paragraph with Advisory identifier: pending.
  • Control documents. README, ARCHITECTURE, PRODUCT_BRIEF, ROADMAP, RELEASING and docs/vnext/README.md gain "v0.22.0 is the current release candidate. It is not published." and keep v0.21.1 as the latest published release. CURRENT_STATE.md gets a "What v0.22.0 Targets" section above "What v0.21.1 Shipped".
  • docs/alpha/known-limitations.md is unchanged (see "Not fixed here").

Tests

  • New tests/unit/test_v0220_release_notes.py, 27 tests, 54 cases, modelled on the v0.21.1 test as it was in Release v0.21.1 #667 before the tag. It pins the pending notes and no checksums file, the size ceiling (17,500; the notes are about 14,400) and the section order, the six version sites and the marketplace pin, the candidate lines, the dated heading and the empty Unreleased section, both forms of the old marker, the dash and security wording and the pending advisory identifier, the seven upgrade steps, the numbers that drift (tool counts, the revision, the vault cap, the cache limit, the timeout, the pause, the 32 character floor, the prefix), the five settings and the two flags (read from the v0.21.1 export and from this tree), the package contents rule, and release_check on the real tree. It also runs the claims of the notes:
    • the endpoint rules (7 spellings on this machine, 9 not, and a proxy) and the opt-in values (1, true, yes and others leave it off);
    • the policy decision of each kind of request to the agent output route (9 kinds, plus the domain and sensitivity cases), and the shape of the route against the tag: the blocked test before the service call, the VNextCaptureValidationError in the except, the refusal in the connector service, none of them at v0.21.1;
    • import-markdown, doctor and reindex-embeddings --sources --drop against a loopback endpoint that records every text: nothing sent by default, the search_document: prefix when on, the table made and dropped, a 127.1 endpoint leaving every chunk pending, links only and too short chunks not sent, a dry run sending nothing;
    • the code of the v0.21.1 tag, exported with git archive into a temporary folder and run in a subprocess: a vault that never turned the opt-in on opens and exports, a vault with vectors opens but its export fails with export_failed until --drop, a vault v0.21.1 wrote opens here, ALICE_SEARCH_QUALITY=vectors raises where this tree accepts it, and the Alembic folders are identical.
  • test_v0211_release_notes.py: the version site test no longer reads the version sites, which belong to the v0.22.0 test now, and is renamed test_the_marketplace_pins_the_published_release_and_the_notes_carry_its_install_lines, as Release v0.21.1 #667 did for the v0.21.0 test. The release check test runs the pre-tag rule for 0.21.1 explicitly. tomllib import removed with it.
  • The tests that index the changelog by position move down one section: test_v0200_release_notes.py, test_v0202_release_notes.py, test_v0210_release_notes.py, test_v0211_release_notes.py, test_data_dir_guard.py, test_mcp_readonly_hints.py, test_claude_code_plugin.py.
  • Each docstring names the mutations that fail its test. 26 mutations on test_v0220_release_notes.py, each one applied to a clone of this head with an exact single-match replace (or a created file), the named tests run with a green baseline first, and the file restored from saved bytes: all 26 fail the test they name (title, state comment, a section, a plugin pin, the candidate line, an entry under Unreleased, the old marker in a doc, a dash, the pending identifier, an upgrade step, the vault cap default, a number in the notes, .localhost dropped from the endpoint rule, 1 accepted as the opt-in, the route guard, the service refusal, unknown agents allowed to write, --drop leaving the table, the bootstrap making the table, a migration file, scripts added to the packages, the stale sentence back, the document prefix, a new setting name, the links rule, the loopback rule). 14 more on the edited existing tests: the v0.22.0 heading redated against the seven tests that index the changelog by position, the v0.21.1 heading renamed, the old marker in a v0.21.1 entry, the marketplace ref, sha and install line, the v0.21.1 notes state and the checksums file against the renamed test. All 40 fail the test they name.
  • scripts/derived_label_mutations.json: line and sha256 refreshed on the 97 edits that name CHANGELOG.md (43), docs/alpha/mcp-tools.md (52) and CURRENT_STATE.md (2). Every before text still occurs once. All 97 cases were replayed with scripts/verify_derived_label_mutations.py --only NAME --output DIR against head 913d3225 (97 names, 97 results): 97 of 97 killed by the test they name, with a green baseline. No case names a test file that this PR changes. test_derived_label_mutation_manifest_matches_tree.py passes.

Claim checks

Every sentence of the notes that states a behaviour was run against this branch and against an export of the v0.21.1 tag (git archive v0.21.1), each with its own PYTHONPATH, through the real entry points: the mounted ASGI application on the local PostgreSQL test database (a fresh database per test), alice-memory import-markdown, import-chatgpt, export, import, doctor, sources and reindex-embeddings, and alice-memory mcp over stdio (JSON-RPC tools/call). The embeddings endpoint was a small server on 127.0.0.1 (and one on ::1) that records every text it receives. No other host was contacted. Verdicts below are v0.21.1 then this branch.

Check v0.21.1 This branch
POST /v0/vnext/agents/ingest-output, read_only_agent key HTTP 201; +1 source, chunk, artifact, provenance link, 2 identity events, agent.policy_blocked; ids in the body null, decision blocked HTTP 403 agent policy blocked this action; no row in those tables; events policy.decision, agent.policy_blocked, 2 agent.identity_upserted; +1 agent_identities
the same with propose_memory 201; +1 candidate memory too 403; no memory
memory_proposal_agent key; project_scoped_agent key asking for health 201 and rows written 403, nothing written
no key, agent_id kiln-bot, no profile 201 and rows written 403, nothing written
no key, agent_id hermes or openclaw; declared admin_agent; trusted_local_agent key 201, rows written 201, rows written (same)
no key, kiln-bot declaring read_only_agent 201 403
token in the title, the content or a source ref (trusted key; no key as hermes) HTTP 500 (CaptureCredentialRefused raised past the middleware), nothing written HTTP 400 vNext agent output ingest request is invalid, token not repeated, nothing written
POST /v0/vnext/sources with the same read-only key 403 403, same body apart from the trace id
MCP tool alice_vnext_ingest_agent_output and alicebot vnext agents ingest-output, read-only profile refused, 0 rows refused, 0 rows (same); the same CLI call with trusted_local_agent writes
the route against a SQLite URL fails at the PostgreSQL connection; alice-memory has no serve command
rows v0.21.1 wrote for a blocked request source agent_output with metadata_json.policy_decision.decision blocked; artifact needs_review; memory candidate
import-markdown with the endpoint variables set and no opt-in 0 texts sent 0 texts sent; no chunk_embeddings in the receipt; no table; ALICE_SOURCE_EMBEDDINGS of 1, true, yes: 0 texts
the same with ALICE_SOURCE_EMBEDDINGS=on 0 texts sent all chunks sent, 5 of 5 embedded for the 3 note folder; text search_document: <title>...; table source_chunk_embeddings made
the same into localhost, embed.localhost, 127.0.0.1, [::1] 5 of 5 sent each
the same into 127.1, 192.0.2.1, or 127.0.0.1 with http_proxy set 0 sent; 5 pending endpoint_not_on_this_machine in 0.7 s
a # T note with ok, a links only note; --dry-run skipped too_short 1 and link_only 1; dry run reason dry_run, 0 sent
--sensitivity confidential chunks sent
alice_capture and import-chatgpt, endpoint set and opt-in on no chunk_embeddings, 0 texts sent chunk_embeddings in the receipt, 1 text sent for each; with the opt-in off, no chunk_embeddings and none sent
alice-memory doctor 5 more lines, and no other line differs, in a vault with the opt-in off
sources delete, sources prune, import-markdown --supersede on a vault with vectors receipts count chunk_vectors (2 deleted with a source of 2 chunks; prune counts 0 after a supersede already removed them), and retained_data names vectors
export of a vault with vectors export_failed, exit 1 exits 0, 25 records, note "this vault holds 5 source chunk vectors, and none are exported"
import of that export "5 source chunks imported without vectors"
reindex-embeddings --sources --drop 5 dropped, 0 texts sent, table gone; v0.21.1 then exports the vault
doctor, brief, recall, import-markdown of v0.21.1 on a vault with vectors work
a vault v0.21.1 wrote, opened here with doctor, brief, export, alice_recall works; no table made
alice_recall with ALICE_SEARCH_QUALITY=vectors tool_request_failed works; with the opt-in and the endpoint, retrieval.stages.sources source vectors, vector.status enabled, a second request with the search_query: prefix
the same with the opt-in off disabled: source embeddings are off; same sources as passage
alice_recall, 5 queries, debug on, no new setting; and again on a vault with vectors with the opt-in on and the endpoint set the same bytes as v0.21.1 for all 5, in both runs
alice_recall with ALICE_SEARCH_QUALITY unset or passage, opt-in on, endpoint set, vault with vectors one request (the memory query) the same one request; with vectors there are two, the second with the search_query: prefix
recall_source_ranking with vectors on the PostgreSQL store passage (unit test)
git diff --stat v0.21.1 origin/main -- apps/api/alembic workers empty
wheel and sdist built from this head with python -m build --no-isolation 392 and 422 files; no file from scripts/ or apps/web; the four new vector modules are in the wheel
the legacy tool alice_vnext_ingest_agent_output on a SQLite vault tool_execution_failed tool_execution_failed (same)

Three things the check turned up, which the notes handle:

  • The changelog entry for Refuse a blocked agent policy decision at the agent output ingest route #680 says "embedding job". There is no job table. The route calls _persist_vnext_deferred_embeddings after its commit, v0.21.1 called it with zero inputs for every case above (a candidate memory is not embedded), and this branch does not reach it for a blocked request. The notes say "memory" and make no claim about an embedding job; the changelog sentence is as merged.
  • A SQLite vault that holds chunk vectors cannot be exported by v0.21.1. "No migration" is true, and the notes add an upgrade step (6) for going back.
  • The docs say only the value on turns ALICE_SOURCE_EMBEDDINGS on. The code reads it case-insensitively (ON counts). The notes state only that 1, true and yes leave it off.

Validation

Run on head 913d3225 in a worktree, with the repository's own Python and PYTHONPATH set to the worktree's apps/api/src.

  • python scripts/release_check.py and with --require-finalized-release-docs: Release check: PASS (alice-memory 0.22.0) for both.
  • python scripts/check_control_doc_truth.py: PASS (16 documents verified).
  • python scripts/check_commit_authors.py --base origin/main --head HEAD: PASS (3 commits).
  • scripts/check_protected_paths.py categorization of the 27 changed files: no protected area is touched.
  • ruff check on the changed Python files: clean.
  • Unit tests, the five shard selections of tests.yml, each run as python -m pytest <selection> -q -p no:cacheprovider on this head, the five in parallel, from a clean tree with the logs outside it (the five lists name 658 files, which is every tests/unit/test_*.py, once each; the host home guard refused 0 path checks in each):
    • shard 1 (test_[p-r]*, test_saved_p*, test_[t-w]*): 5,971 passed, 0 failed, 2 skipped
    • shard 2 (test_[0-9a-c]*, test_s[!aoq]*, test_saved_quotes_*): 4,227 passed, 0 failed, 11 skipped
    • shard 3 (test_[j-o]*, test_s[oq]*): 14,997 passed, 0 failed, 23 skipped
    • shard 4 (test_saved_quote_*): 488 passed, 0 failed
    • shard 5 (test_[d-i]*): 2,717 passed, 0 failed, 4 skipped
    • Total 28,400 passed, 0 failed, 40 skipped (v0.21.1 had 28,055 passed, 40 skipped). The same five runs on the first commit of this branch gave the same counts.
  • pytest eval/longmemeval -q: 218 passed.
  • pytest tests/integration/test_ingest_output_policy_postgres.py against the local PostgreSQL 16: 22 passed on this head. The same file copied into an export of the v0.21.1 tag: 15 failed and 7 passed (the 7 are the key-bound-to-a-project cases and the allowed writes, which v0.21.1 already handled).
  • Mutations: 40, listed under Tests, all failing the test they name.
  • Manifest: 97 of 97 replayed cases killed with a green baseline, from 913d3225.
  • Before the commits, nine tests failed as expected (the position-indexed changelog tests and the v0.21.1 version and release check tests) and were updated as described under Tests; no other test failed.
  • The added lines hold no em or en dash except the required CHANGELOG heading, no home path, machine name or personal detail, and none of the words the repository keeps out of its text apart from the pinned disclosure sentence of the Security section (scanned over the diff). An earlier draft of the new test held its dash characters as literals; the scan found them and they are escapes now.
  • Not run here: the performance suites, the integration suites other than the route's, make release-check, the web tests, the real-host jobs, and the publish-recheck-rehearsal.yml run itself. CI runs the required ones, and the rehearsal is dispatched on the merge commit before the tag.

Not fixed here

  • docs/alpha/known-limitations.md still says v0.21.0, as it did after v0.21.1, and five tests pin its header to v0.21.0. It does not list the limit that remote embeddings endpoints are not supported for source text, which the notes, SECURITY.md and docs/alpha/mcp-tools.md state.
  • docs/alpha/mcp-tools.md says only the value on counts for ALICE_SOURCE_EMBEDDINGS; the code accepts ON too. 52 manifest cases cite that file, so a wording fix there belongs in its own change.
  • The changelog entry for Refuse a blocked agent policy decision at the agent output ingest route #680 says "embedding job", see above. It is as merged.
  • Four manifest cases that Release v0.21.1 #667 named (pytest ids that no longer exist) were not touched.

What is left for after publication

The same mechanical change as after v0.21.1: add docs/release/v0.22.0-checksums.txt and set the notes state to published and recorded; fill in the advisory identifier where the notes say Advisory identifier: pending. and change the test that pins the sentence; move the statements that name the latest published release, the baseline and the checksums to v0.22.0 (README, ARCHITECTURE, PRODUCT_BRIEF, ROADMAP, RELEASING, CURRENT_STATE, docs/vnext/README.md) and drop the candidate lines; move the marketplace ref and sha to the v0.22.0 tag commit and the sentences that name the v0.21.1 pin; move the install and checkout lines; add the v0.22.0 notes and changelog section to test_published_release_notes_stay_immutable.py; turn the pending-state tests of test_v0220_release_notes.py into the published form; refresh line and sha256 in the manifest.

Upgrade Overview

Protected Areas

  • memory schema
  • evidence pipeline
  • trust rules
  • promotion logic
  • continuity APIs

None is touched. scripts/check_protected_paths.py categorizes none of the 27 changed files. The changes are version strings, documentation, tests and the mutation manifest.

Compatibility Impact

No code change in this PR. The code v0.22.0 ships is the code on main. The package version moves from 0.21.1 to 0.22.0, and the MCPB manifest and the Claude Code plugin pins move with it. The marketplace file still pins the v0.21.1 tag commit until the post-publication change.

Migration / Rollout

No migration is added. PostgreSQL stays at revision 20261011_0097. A SQLite vault opens in v0.21.1 and v0.22.0 either way, except that a vault which holds chunk vectors has to be dropped with alice-memory reindex-embeddings --sources --drop before v0.21.1 can export it. Tagging, the release gate, the rehearsal run and publication are not part of this PR.

Operator Action

None for this PR. Before the tag, dispatch publish-recheck-rehearsal.yml on the merge commit and confirm its run is on the SHA to be tagged.

Validation

scripts/release_check.py (with and without --require-finalized-release-docs), scripts/check_control_doc_truth.py, scripts/check_commit_authors.py, the protected-path categorization, ruff check on the changed Python files, the five unit shard selections of tests.yml, pytest eval/longmemeval, the route's PostgreSQL test file, and the manifest replays above.

Rollback

Revert the merge commit. Nothing is tagged or published by this PR, so there is no external state to undo.

Commits after 913d3225

  • c0f566b6 Say which agent output requests the policy blocks. A sensitivity outside a key's labels does not block the request on its own: run on this branch against the local PostgreSQL 16, a trusted_local_agent key and a project_scoped_agent key that ask for confidential or regulated get HTTP 201, the decision allowed_with_filtering (restricted_sensitivity_filtered), and one source and one artifact. The notes said that such a key is refused, in upgrade step 3 and under Security; both now name domains only, as the CHANGELOG entry does, and one sentence says that sensitivity alone does not block, as in v0.21.1. The release notes tests (776 in 25 files), release_check.py plain and with --require-finalized-release-docs, and check_control_doc_truth.py pass.
  • 91dfdea7 Find the package list without setuptools in the v0.22.0 notes test. CI's environment does not install setuptools, so test_the_package_holds_none_of_the_bench_scripts_the_walkthrough_or_the_console failed in unit shard 1. The test now walks the packages itself and finds the same lists as find_packages for apps/api/src (10) and workers (1). The file passes with setuptools hidden (54 passed), and a scripts package created under apps/api/src fails the test.

Move the six version sites to 0.22.0, turn the Unreleased changelog entries
into the dated v0.22.0 section, name v0.22.0 as the current release candidate
in the control documents, and add the release notes with their pending state.
The notes cover the agent output route that now refuses a blocked request, and
the opt-in vectors for the chunks of notes, which are off by default and have
no published measurement.

The notes have a test that runs their claims: the endpoint rules, the opt-in
values, the off-by-default import, the policy decision of each kind of request,
and the v0.21.1 side of each comparison from an export of the tag. The earlier
release notes tests move one changelog section down, the mutation manifest is
re-pinned to the changed files, and the three documents that said the
continuity page and the walkthrough were on main now say from v0.22.0.
…angelog

The new test held its dash characters as literals. They are escapes now, as
in the tests of the earlier notes. One changelog entry called a check by a
word the repository keeps out of its own text, so it says check, and the
manifest digests of the changelog are refreshed.
@samrusani
samrusani marked this pull request as ready for review October 26, 2026 11:40
@samrusani
samrusani merged commit a6a5f49 into main Oct 26, 2026
43 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant