Skip to content

v2.21.0

Latest

Choose a tag to compare

@cirwel cirwel released this 04 Sep 21:05
· 2 commits to master since this release
53290e2

Server release cut at 53290e22. Deploy is continuous off master, so this tag is a citation anchor and rollback target, not the delivery gate — everything here has been running.

148 merged changes since v2.20.0: 33 added, 9 changed, 48 fixed, 1 removed, 28 documentation. Full detail in docs/CHANGELOG.md.

What this release is about

This is the release where the outside of the system became specified.

A public interface contract. docs/interface-contract.v1.json and src/interface_contract.py publish a versioned, transport-neutral tool contract — schema unitares.interface-contract.v1, version 1.1.0 — spanning MCP streamable HTTP, REST /v1/tools, and stdio, with workflow aliases advertised consistently and a surface_sha256 over the canonical surface so a peer can detect drift without diffing.

A federation handshake. list_tools(lite=true) carries a federation block a peer can negotiate against without prior knowledge: where to find the contract, the MCP range actually supported (>=1.26.0,<3.0.0, majors 1 and 2 both tested, newest-in-range CI blocking), and the unitares.lifecycle-envelope.v1 success/failure envelope with the four lifecycle capabilities a Resident must implement — start_session, sync_state, check_working_state, record_result. Paired with the separate cirwel/unitares-resident repo, cross-pinned to contract commit d044d627.

Identity-bound coordination. The Elixir lease plane is packaged into the Tier-1 Docker Compose stack, and make coordination-demo proves acquire → held-by-other refusal → atomic handoff → status → release → bounded cleanup end to end. Lease mutations bind to a caller's governance identity through a short-lived Ed25519 lat.v1 attestation bound to deployment audience, holder UUID, method, path and exact request-body hash, with each (issuer, jti) consumed once in Postgres before mutation.

Answers before diagnostics. Check-in responses lead with an action-first envelope — normalized action, one-line reason, risk score, verdict confidence, evidence basis — with legacy ODE-derived coherence separated into an explicit non-behavioral block.

consult lands as the canonical advisory model-inference facade, with explicit purpose / effort / privacy / degradation contracts and REST parity. request_review remains the distinct governed peer-review verb.

Identity honesty. A fresh mint that misses the resident roster now says so in the response — status, on_roster, granted_tags vs required_tags, and a remedy — instead of silently minting an ephemeral identity that reports success and is archived later. Relatedly, is_agent_protected no longer grants archival immunity by label.

Where federation actually stands

The primitives are real and running. The multi-principal deployment is not, and this release does not claim it.

  • Single trusted issuer. Lease attestation v1 accepts one issuer. Multi-issuer federation stays deferred until leases persist (issuer, subject) principals.
  • Resolution attestations are symmetric. They are HMAC-keyed on each agent's api_key, so a third party able to verify a signature could also forge one. A resolution record is therefore not independently verifiable today by an operator who does not already trust its issuer. This is a stated seam, not an oversight.
  • The federated EISV exchange is a pilot. Ed25519-signed and k-anonymity-enforced, but outputs stay PILOT_AGGREGATE_ONLY with decision_authority: NONE, collection is disabled, and it enrolls no cohort and authorizes no paired score/outcome access.
  • Non-self-clearing — a paused agent cannot clear its own session over a standing reviewer objection — is named as a federation seam in the threat model.

Compatibility

  • mcp 1.29.0 → 2.1.1 (major). Unhandled tool/resource/prompt exceptions now log server-side and reach the client only as a generic message unless raised through ToolError / ResourceError. The 1.x/2.x compatibility accessor covers the inputSchemainput_schema rename; mcp-newest is a blocking lane, so the newest in-range resolution can no longer silently become the tested configuration.
  • Production interpreter is Python 3.14. constraints.txt carries a production-python: marker and CI holds four surfaces to it (Dockerfile base, scripts/ops LaunchAgent templates, the test matrix). Minor-series compatibility is the contract; patch-level parity is not claimed.
  • src/research_registry.py removed, with its MCP handler and schema, the three /v1/research/* routes, the dashboard tab, tests and ops doc. Its one distinguishing feature graded any non-empty free-text source as "anchored". Callers of /v1/research/* must drop them.
  • Label-based archival immunity is gone. Protection derives only from server-granted pioneer / persistent / pinned tags, which an identity cannot self-assign.

Migrations

None required. No schema migration gates this release.

Evidence

  • Release Seams green at the tagged commit: changelog coverage 148/148 cited over a --first-parent denominator (2 release-chore excluded, 10 declared no-user-effect), every tracked release series level with its tag.
  • Skills bundle re-cut and reachable: unitares-governance-plugin v0.4.17 mirrors skills/ byte-for-byte with a regenerated SKILLS_MANIFEST.sha256.
  • Docker Quickstart passed on a5546835, the newest container-input commit in the range; the two later constraints.txt commits (#2058, #2060) are comment-only, no pin moved.
  • Suite runs on both 3.12 and 3.14 across eight database-backed shards; the Elixir wave3a_handlers suite (83 tests) gained the CI coverage it had lacked since #1887.

Known limits

  • constraints.txt is a container build input (Dockerfile:33) but is not in the Docker Quickstart path filter. It did not matter here because both in-range edits were comments, but a real pin change would slip that gate.
  • seams is still not a required status check in branch protection; it is a gate by convention.

Rollback

ghcr.io/cirwel/unitares:v2.20.0, or git checkout v2.20.0. Nothing in this release writes irreversible state.