title: v0.4.0 — M4 release: the Autonomous Layer (opt-in), platform operability, and a docs/Learn honesty sweep
description: Release notes for v0.4.0, as recorded in docs/releases/v0.4.0.md.
url: https://legalquants.github.io/lq-ai/changelog/v0-4-0/
checked-against: b7f4d2bc (2026-05-31)
status: draft
kind: explanation
sources: docs/releases/v0.4.0.md

> **Status: DRAFT for the v0.4.0 tag.** Attorney legal-substance walk-through cleared (gate 1).
> Branch ↔ `main` reconciliation is **done** (merge `d336c66`; `origin/main` is now an ancestor)
> and `api` + `gateway` `__version__` are bumped to `0.4.0`. All post-merge gates pass. What
> remains is the **merge to `main` + the annotated `v0.4.0` tag** — see "Release readiness" below.

Milestone 4 turns LQ.AI from an assistant you drive into one that can also **run on its own — but
only when you opt in, and only inside hard brakes**. The layer is **off by default**; nothing runs
autonomously until an operator turns it on per-user in Settings. Every autonomous run is bounded by
a cost cap, an external halt + idle watchdog, and per-phase tool limits, and emits an inspectable
receipt. This release also ships the operability surfaces that make the layer discoverable and
self-explanatory, and a thorough reconciliation of the docs and Learn content to what the code
actually does.

---

## Headline — the Autonomous Layer (M4)

A new **Autonomous** area (opt-in, off by default; enabled per-user in **Settings → Autonomous**).

**What it runs**
- **Schedules** — a chosen skill or playbook on a cron cadence, optionally scoped to a knowledge
  base and/or matter, with a per-run cost cap.
- **Watches** — a run triggered when a document is attached to a chosen knowledge base.
- **Run now** — a one-off, on-demand run of a skill/playbook so you can see the result (and its
  receipt) before arming a schedule or watch.

**How it runs** — a LangGraph phase machine (intake → analysis → drafting → ethics review →
delivery) that performs real in-loop agentic work through the same guarded chokepoint as the rest
of the platform: every tool call (retrieve / run-skill / run-playbook) passes through
`guarded_tool_call` with audit + OpenTelemetry spans, and a tolerant structured-output parser that
completes honestly rather than crashing on malformed model output.

**Safety brakes (all live, all leave a receipt)**
- **R4 — cost cap.** Per-trigger `max_cost_usd` (default $5, configurable via
  `autonomous_default_max_cost_usd`); a run that would overspend is halted with
  `terminal_reason = cost_cap_reached`. Live-verified during fresh-install acceptance.
- **R5 — external halt + idle watchdog.** A run can be halted from the UI; a cron watchdog moves an
  idle run running → paused → halted over two idle ticks.
- **R6 — per-phase tool limits.** Each phase is bounded in how many guarded calls it may make.

**Where results land**
- **Sessions** — every run with its chronological, inspectable **receipt**.
- **Memory** — per-user curated memory (keep / edit / dismiss / delete); only kept items are
  injected.
- **Precedents** — a precedent board (`propose_precedent`), with promote-to-Matter.
- **Proposals** — project-context proposals (accept / reject).
- **Notifications** — in-app notification rail with an unread badge; **best-effort email**
  dispatch (SMTP transport, timeout-bounded — in-app is the source of truth).

**Opt-in enforcement** — mutate endpoints are gated on the per-user `autonomous_enabled` flag
(read + halt stay open so you can always inspect and stop); schedule/watch spawn paths skip
opted-out users.

---

## Platform operability (Phase 1 of the platform-cohesion build, design §4)

Made the (off-by-default) layer discoverable and honest about its own scope:

- **§4.1 Home discoverability signpost** — an Autonomous card on Home for *all* users; links a
  not-yet-enabled user straight to the opt-in (**Settings → Autonomous**), or to the Autonomous
  area when already on. Resolves the chicken-and-egg where the tab was hidden until enabled and
  nothing pointed to the toggle.
- **§4.2 Configure / education tab** — a plain-language page explaining On/Off, Schedules vs
  Watches, Run-now, where results land, and the R4/R5/R6 safety model; plus instructive
  empty-states on Sessions / Schedules / Watches.
- **§4.3 Cost-cap field** in the schedule/watch create modals, and **readable target/KB/matter
  names** in list rows (no more raw IDs).
- **§4.4 Run-now** — backend `POST /autonomous/run-now` (`trigger_kind='manual'`, reusing the
  executor + brakes), its API client, and the Sessions-page UI + Cypress smoke.
- **§4.5 Tabular honesty fix** — corrected a Citation-Engine overclaim in the tabular docs to
  describe display-only source-chunk references (DE-309).

---

## Documentation & Learn honesty sweep (M4-D2)

A pass to make every user-facing claim match the shipped code:

- Rewrote **HONEST-STATE** as the M1–M4 capability truth-map and reconciled README, PRD §3.10 +
  brake registers, architecture, db-schema (migrations 0001–0045), observability (spans / attrs /
  audit actions), security boundary registers (R4/R5/R6 → shipped), and the tabular / citation /
  skill-authoring / quickstart docs to source.
- New `docs/autonomous-layer.md` feature reference; ADR 0013 for the autonomous-layer design.
- **Learn:** corrected stale playgrounds and pages (including a fabricated skill list and a stale
  "M4 planned" status), and added **4 new How-It-Works playgrounds** — Autonomous flow, Autonomous
  primitives, Intake bridges, KB hybrid retrieval, Matters/Org-profile/Privilege-tier — each
  field-checked against source.

---

## Fixes & hardening

- **DE-325** — `build_receipt` call sites hardened so a receipt-build failure can't crash the
  worker; brake-halted (R4/R5) sessions still surface their `terminal_reason`.
- **DE-326** — fresh-install worker/api alembic-migration race fixed in `docker-compose.yml`
  (single migrator; workers wait for api-healthy).
- Standard-cron DoM/DoW OR-semantics + poison-schedule guards; naive-datetime rejection in
  `retrieve_chunks` since-mode; race-safe precedent upsert.

## Schema

- Migration head **0045** (per-trigger `max_cost_usd` on watches + schedules). Phase 1 added no new
  migration.

---

## Honest scope — what did *not* ship (deferred)

- **DE-287** — Word add-in in-pane skill/playbook execution; the add-in surface remains deep-link
  placeholders + an inert tier badge by design.
- **DE-309 / DE-310** — tabular per-cell resolvable citations / per-cell cost+tier telemetry
  (cells persist `cost_usd: "0"`, `tier_used: null`; the pre-flight estimator is unaffected).
- **DE-319** — LangGraph held at 0.2 for M4 (0.2 → 1.x migration deferred).
- **DE-321 / DE-322** — watch firing under a future KB-sharing model; playbook/project FK
  ownership validation on schedule/watch create.
- **DE-323 / DE-324** — autonomous proposals on the Matter detail page; a global-chrome
  notification bell.
- **DE-327** — Helm/k8s worker-migration parity (the DE-326 single-migrator guarantee lives only
  in compose; the Helm chart has no worker deployments yet).
- **DE-328** — `skill_inputs` collected in the UI don't yet reach the model for non-templated
  skills (gateway assembler change; first of the post-M4 Donna backend asks).

The platform-cohesion design's §3 model and §5 roadmap (Phases 2–5) are **recommendation-only** and
were intentionally **not** built in this release.

---

## Release readiness

**Branch ↔ `main` reconciliation — DONE.** `feat/lqvern-m4-autonomous` had diverged from `main` at
`d54df6b` (before v0.3.1) and was missing 10 main-only commits. Merge `d336c66` brought them all in
— `origin/main` is now an ancestor of the branch. The merged-in commits:

| main commit | PR | what |
|---|---|---|
| `8b8e549` | #96 | **DE-305** default-install fix — bridge vars `${VAR:-}` not `${VAR:?}` |
| `82d7874` | #97 | version bump `0.3.0 → 0.3.1` |
| `3e5809b` | #98 | CI: don't upload SBOM as a Release asset |
| `0101b65` | #99/#101 | remove dead paddleocr placeholder breaking `--profile local` (now DE-320) |
| `4df3b9b` | #102 | chat-receipts: surface `anonymization_applied` + `message_id` |
| `7c7ce14` | #103 | gateway: persist `inference_routing_log` on streamed completions |
| `9672ef4` | #104 | observability.md span/attribute correction |
| `438198c` | #105 | document `/v1/models` alias fields |
| `5df44b7` | #106 | add `ROADMAP.md` + README contributor anchors |

Four doc conflicts were resolved keeping the more-recent/accurate side while preserving both sides'
substance (PRD §3.10 dedup + kept-both DE sets incl. DE-320; HONEST-STATE §9 PaddleOCR correction;
observability §3 source-reconciliation; the alignment guide's shipped `propose_precedent`). `api` +
`gateway` `__version__` are bumped to `0.4.0`.

**Post-merge gates — all green:** web `check:lq-ai` 0 errors + vitest 692/692; api `ruff`/`mypy`
clean + pytest 95 passed/276 skipped; gateway `ruff`/`mypy --strict` clean + pytest 529 passed/2
skipped.

**Remaining steps (maintainer):**
1. Merge `feat/lqvern-m4-autonomous` → `main` (fast-forward is possible since `origin/main` is an
   ancestor; a `--no-ff` merge commit is fine too).
2. Tag `v0.4.0` (annotated, using the message above), push the tag to both remotes — the existing
   Release workflow builds + signs the images and attaches the SBOM.
3. Optionally rebuild the live stack (`docker compose build web && up -d web`) on the merged `main`.

---

*Drafted from the `main..feat/lqvern-m4-autonomous` inventory; reconciled branch HEAD `d336c66`
(post-merge, 0.4.0). Per-task review trail and verification results are in the Phase-1 plan and the
`docs/LQVern/HANDOFF-2026-05-31-…` brief.*

## Next

- [Upgrade](/lq-ai/operate/upgrade/) — the runbook for taking this release.
- [Release versioning](/lq-ai/reference/versioning/) — what a patch and a minor each commit to.
- [All release notes](/lq-ai/changelog/) — every tag, and which have notes.
