# Assay v3.1.0 Release Runbook

**Target date**: 2026-03-15
**Release type**: minor feature release

## Why v3.1.0

This line carries the Wave24-Wave42 MCP policy-enforcement stack forward from `v3.0.0`.

Why this is a minor release instead of a patch:
- additive but material expansion of decision and evidence payloads
- new runtime enforcement for `approval_required`, `restrict_scope`, and `redact_args`
- normalized replay/diff and consumer-facing payload contracts
- stronger downstream compatibility expectations for decision, replay, and context-envelope readers

This line is intended to stay backward-compatible for additive readers, but it is not small enough to hide inside a patch release.

## Scope

Wave clusters included in this release line:
- Wave24: typed decisions + Decision Event v2
- Wave25-Wave26: bounded `log` and `alert` obligation execution
- Wave27-Wave28: approval artifact contract + `approval_required` enforcement
- Wave29-Wave30: `restrict_scope` contract + enforcement
- Wave31-Wave32 + Wave36: `redact_args` contract + enforcement hardening
- Wave33 + Wave35: obligation fulfillment normalization
- Wave34 + Wave40: fail-closed / deny evidence typing and convergence
- Wave37-Wave42: decision/evidence convergence, replay diff basis, evidence compat, consumer hardening, context-envelope hardening

## Consumer impact summary

Downstream consumers should expect additive changes in MCP decision and replay payloads, including:
- typed decision / outcome fields
- richer obligation and fulfillment metadata
- approval, scope, and redaction evidence fields
- replay diff basis and compatibility markers
- deny/evidence convergence markers
- consumer-hardening and context-envelope completeness markers

No new control-plane, auth transport, or external workflow semantics are introduced by this release line.

## Publishability Matrix (Advisory)

| Crate | Publish | Wave24-Wave42 impact | Semver advice | Notes |
| --- | --- | --- | --- | --- |
| `assay-core` | yes | direct | minor | Main MCP policy/enforcement, decision, replay, and evidence changes landed here. |
| `assay-cli` | yes | likely direct | minor | CLI consumes and emits machine-readable reporting tied to the new decision/evidence surfaces. |
| `assay-mcp-server` | maybe | indirect | patch or none | Only publish if crate surface or dependency lockstep is required for this line. |
| `assay-common` | maybe | indirect | patch or none | Publish only if downstream users consume changed shared public types directly. |
| `assay-policy` | no by default | low | none | No clear standalone publish signal from this wave set. |
| `assay-evidence` | no by default | low | none | Earlier waves touched evidence more heavily than this sequence. |
| `assay-monitor` | no by default | low | none | Not a Wave24-Wave42 hotspot. |
| `assay-metrics` | no by default | low | none | Not a primary surface in this release cluster. |
| `assay-sim` | no by default | low | none | Not a primary surface in this release cluster. |
| adapters / registry / ebpf / xtask | no by default | low | none | Only bump if older unreleased work needs to ship on the same tag. |

Practical note: this workspace uses a shared release line, so the repo version bump is `3.1.0` even if only a subset of crates is the primary consumer-impact target.

Automation note: the current `release.yml` default publish path is broader than the impact-based matrix above. The workflow runs `scripts/ci/publish_idempotent.sh`, which publishes in this order by default: `assay-common`, `assay-registry`, `assay-evidence`, `assay-adapter-api`, `assay-core`, `assay-metrics`, `assay-policy`, `assay-mcp-server`, `assay-monitor`, `assay-sim`, `assay-cli`. Treat the matrix above as semver and consumer-impact guidance, not as an override of release automation.

## Preflight

```bash
git fetch origin --tags
git checkout main
git pull --ff-only
rg -n '^version\s*=\s*"' Cargo.toml crates/*/Cargo.toml assay-python-sdk/Cargo.toml -g 'Cargo.toml'
git tag --sort=-creatordate | head -n 10
```

Expected before cut:
- previous release tag visible: `v3.0.0`
- workspace version aligned to `3.1.0`
- no mixed internal crate versions in `Cargo.toml`

## Mandatory Release Gates

```bash
PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 cargo test --workspace
PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 cargo clippy --workspace --all-targets -- -D warnings
```

Build / artifact sanity:

```bash
cargo build --release -p assay-cli
./target/release/assay --version
```

Replay / MCP smoke checks:

```bash
BASE_REF=origin/main bash scripts/ci/review-wave42-context-envelope-step2.sh
BASE_REF=origin/main bash scripts/ci/review-wave42-context-envelope-step3.sh
PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 cargo test -p assay-cli mcp_wrap_coverage_cli_smoke_writes_report
```

Python / PyPI sanity:

```bash
cd assay-python-sdk
python3 -m build
python3 -m twine check dist/*
cd -
```

## Release Notes Checklist

Before tagging, make sure the final GitHub release notes call out:
- typed decisions + Decision Event v2
- approval / restrict_scope / redact_args enforcement additions
- replay-diff and evidence-compat additions
- deny-evidence convergence
- consumer/read precedence and context-envelope hardening
- additive payload fields that downstream readers may want to consume

## Tag + Publish

```bash
git tag -a v3.1.0 -m "Assay v3.1.0"
git push origin v3.1.0
```

Then let `release.yml` build release assets, publish the default crate set, build Python wheels from `assay-python-sdk`, and publish the PyPI artifacts.

## Rollback / Abort

If mandatory gates fail:
- do not tag
- fix forward on the release-prep branch
- rerun gates

If a partial publish occurs:
- do not retag `v3.1.0`
- cut `v3.1.1` with the forward fix
- document the partial state in GitHub release notes
