# MIND-Mem v3.2.1 release notes

**Released: 2026-04-20**
**Type: Hotfix / production hardening**

v3.2.1 closes the architectural debt called out in the v3.2.0 release
notes:

1. REST request-scoping no longer mutates `os.environ` per-request.
2. OIDC JWTs actually drive the `/v1/admin/*` admin gate.
3. Apply engine block-level ops route through `BlockStore` so
   Postgres-backed workspaces see the writes.

It also cleans up every CI red that followed v3.2.0 — ruff format
drift, Windows path separators, an SBOM `pkg_resources` crash, dead
action SHAs, and a glob-vs-regex typo in `.gitleaks.toml`. No breaking
changes — every v3.2.0 deployment upgrades via `pip install -U
MIND-Mem`.

## Why this hotfix matters

The v3.2.0 release shipped the Postgres backend, REST layer, and
OIDC as **beta** surfaces. The self-audit that accompanied that
release surfaced three CRITICAL architectural issues that would bite
production deployments:

| v3.2.0 beta surface | v3.2.0 bug | v3.2.1 fix |
|---|---|---|
| Postgres storage | `apply_proposal` writes to FS, DB never sees the change | `execute_op` routes through `BlockStore.write_block` |
| Multi-worker REST | Every handler mutates `os.environ["MIND_MEM_WORKSPACE"]`, races under concurrent requests | Per-request `ContextVar` override, set by FastAPI middleware |
| OIDC admin | JWT validated at `/v1/auth/oidc/callback`, ignored everywhere else | `_require_admin` consults `request.state.oidc_scopes` set by `_require_auth` |

All three promote from "beta, known-broken" to "beta, usable."
Postgres still has one more refactor ahead in v3.2.2
(`snapshot(snap_id=…)` API) — that's the last item before Postgres
is labelled GA.

## Key changes

### REST request-scoping (`mind_mem.mcp.infra.workspace`)

New public API:

```python
from mind_mem.mcp.infra.workspace import use_workspace

with use_workspace("/path/to/workspace"):
    # Tool calls inside this block resolve the workspace from a
    # ContextVar override — task-local under asyncio, thread-local
    # through Starlette's thread pool.
    ...
```

The REST app registers an HTTP middleware that wraps every request
in `use_workspace(resolved_ws)`, so handlers never touch `os.environ`
directly. Standalone MCP server still reads `MIND_MEM_WORKSPACE`
from the environment — it's single-workspace by design.

### OIDC admin scopes

JWTs that carry an admin scope authenticate on admin-gated endpoints.
Scope names configurable via `MIND_MEM_OIDC_ADMIN_SCOPES`
(comma/space-separated, default `mind-mem.admin admin`):

```bash
# Use a custom IdP scope
export MIND_MEM_OIDC_ADMIN_SCOPES="mycorp:platform:admin"
```

Invalid JWTs now reject with 401 instead of falling through to the
permissive "no auth configured" path. This closes a silent-accept
bug that applied when `MIND_MEM_TOKEN` was unset but OIDC was
configured.

### Apply engine → BlockStore routing

Five of seven `_op_*` handlers now route through `BlockStore`:

- `append_block` — parses patch as block dict, writes via `store.write_block`
- `update_field` — `store.get_by_id` + mutate + `store.write_block`
- `append_list_item` — same pattern; preserves list / scalar-to-list semantics
- `set_status` — threads store through to the two underlying ops
- `supersede_decision` — marks old block superseded + writes new block

Two remain filesystem-only (`insert_after_block`, `replace_range`)
because they manipulate text ranges that don't have a clean block-
dict representation. No v3.2.0 caller generates these ops; they're
exercised only by hand-written proposals in tests. They're tracked
for v3.2.2.

## CI / plumbing fixes

- Ruff format drift on 25 files (`style: ruff format`)
- Windows path separator in `test_apply_engine_backend_routing.py`
  and `test_workspace_contextvar.py` (cross-drive `os.path.relpath`)
- SBOM crash — pinned `cyclonedx-bom>=5` (3.x imports removed
  `pkg_resources`) in `release.yml` and `security.yml`
- Dead action SHAs — bumped `trivy-action` to v0.35.0; corrected
  `gitleaks-action` v2.3.9 SHA transcription error
- `.gitleaks.toml` `paths[]` regex — `*.pyc` was invalid regex,
  changed to `.*\.pyc$`

## Stability labels after v3.2.1

| Surface | v3.2.0 | v3.2.1 |
|---|---|---|
| Markdown + stdio-MCP | GA | GA |
| Postgres backend | Beta (broken apply) | Beta (usable — last snapshot-API refactor in v3.2.2) |
| Multi-worker REST | Beta (race-prone) | Beta → GA (concurrent-request-safe) |
| OIDC admin gate | Beta (unreachable) | Beta → GA (OIDC-only deployments work) |

## Upgrade notes

- **From v3.2.0:** `pip install -U mind-mem`. No config changes
  required. New optional env var `MIND_MEM_OIDC_ADMIN_SCOPES` if
  your IdP uses non-default admin scope names.
- **From v3.1.x:** see the [v3.2.0 release notes](v3.2.0-release-notes.md)
  for the Postgres / REST / OIDC rollout; upgrade to v3.2.1 directly.

## Test coverage

- 3680 tests pass (v3.2.0 was 3671 → +9 regression tests for v3.2.1)
- Ubuntu × {3.10, 3.12, 3.13, 3.14} matrix green
- macOS × {3.10, 3.12, 3.13, 3.14} matrix green
- Windows × {3.10, 3.12, 3.13, 3.14} matrix green after cross-drive
  relpath fix
- CodeQL + Supply-Chain (pip-audit, bandit, gitleaks, SBOM) green
