title: v0.9.0 — required skill inputs in web chat and gateway reliability
description: Release notes for v0.9.0, as recorded in docs/releases/v0.9.0.md.
url: https://legalquants.github.io/lq-ai/changelog/v0-9-0/
checked-against: 91973fd8 (2026-10-08)
status: draft
kind: explanation
sources: docs/releases/v0.9.0.md

This emergency release restores built-in skills that need required inputs in web chat. In
v0.8.0, the backend enforced those inputs but the composer did not collect them, so attaching
a skill such as NDA Review could fail with `400 skill_input_missing`. The composer now shows
the skill's fields and holds Send until they are ready.

This is a **minor release** under ADR 0025 because the API-to-gateway inactivity timeout changes
from 60 to 900 seconds. Across the 15 merged PRs since v0.8.0, the release also improves Ollama
tool calls, provider configuration, ingestion errors and audit timestamps.

---

## Headline — required skill inputs work in the web composer (#669)

Attaching a skill now loads its input definitions from the backend and displays its required
fields. Optional inputs sit under **More options**. Each attached skill keeps its own values,
so two skills with similarly named inputs do not overwrite one another.

Required document inputs accept pasted text or a ready attached file. File content continues
through the existing attachment path; the form supplies the file name as the skill's document
input. Send is held while required inputs are missing, an attachment is still processing, or
the input schema cannot be loaded. A schema failure offers **Retry** and preserves the draft.
This fixes [#668](https://github.com/LegalQuants/lq-ai/issues/668).
([#669](https://github.com/LegalQuants/lq-ai/pull/669))

The accompanying correction to the [v0.8.0 notes](https://github.com/LegalQuants/lq-ai/blob/91973fd8/docs/releases/v0.8.0.md) records that the earlier claim about
required inputs working in the web composer was inaccurate.

---

## Other changes to read before upgrading

- **The API-to-gateway inactivity timeout rises from 60 to 900 seconds.** Read, write and pool
  timeouts use `LQ_AI_GATEWAY_TIMEOUT_SECONDS`; connection establishment is capped at
  `min(value, 10 seconds)`. Streaming uses the same budget, while short health and configuration
  probes retain their overrides. Review proxy and client timeouts for slower model calls. The
  setting must be positive and finite and should exceed the gateway adapter's `timeout_s`
  (600 seconds by default), so the gateway can report a timeout first. For hand-run deployments,
  recreate `api`, `arq-worker` and `ingest-worker` together after changing `.env`. This bounds
  HTTP inactivity, not total request duration. Setting it to 60 restores the earlier inactivity
  budget but retains the new connection cap; restoring the exact previous behavior requires
  the previous deployment. *(#664)*
- **A declared compatible-provider key must resolve before the provider is used.** An
  `openai_compatible` provider with an unavailable declared key is skipped during discovery.
  Supply the key for an authenticated provider. For an intentionally keyless local server,
  remove the key source or set `api_key_env: ''`, then restart the gateway. The check establishes
  that a key is present, not that it is valid. Returning to the previous behavior for an unset
  declared key requires the previous provider implementation. *(#660)*

Keep a database backup, the previous image digests and the gateway configuration before
upgrading. Apply or roll back the API and both workers together. The
[release runbook](https://github.com/LegalQuants/lq-ai/blob/91973fd8/docs/BUILD-AND-RELEASE.md) describes the deployment sequence.

An installation already on v0.8.0 needs no additional object-store migration. Earlier
installations must also follow the [v0.8.0 notes](https://github.com/LegalQuants/lq-ai/blob/91973fd8/docs/releases/v0.8.0.md) and
[MinIO-to-RustFS runbook](https://github.com/LegalQuants/lq-ai/blob/91973fd8/docs/runbooks/minio-to-rustfs.md). Preserve deployment volumes.

---

## Correctness and user-facing fixes

- **Ollama tool calls work through ordinary and streaming translation.** Arguments are converted
  to the provider's format, and a stream containing only tool calls counts as usable output.
  *(#649)*
- **Gateway configuration defaults apply to empty values as well as unset ones.**
  `${VAR:-default}` expansion now follows that behavior consistently. *(#650)*
- **Failed ingestion exposes its existing error in file metadata**, giving clients the
  `ingestion_error` alongside the failed status. *(#655)*
- **Failed autonomous analysis dispatches receive an error audit row.** A failure after a
  successful dispatch is distinguished as a postprocessing failure. *(#656)*
- **MCP session failures retain bounded cause information and upstream HTTP status**, excluding
  response bodies and full request URLs. *(#659)*
- **OCR citation normalization converges before matching**, so chained character substitutions
  are idempotent. *(#652)*

---

## Test pipeline and documentation

- Nightly Cypress receives the browser-reachable API address and matching CORS configuration.
  *(#630)*
- Property-based checks exercise anonymization, routing and citation invariants. Synthetic PII
  measurement and fixture-integrity checks add a reproducible test surface; they do not establish
  the absence of privacy failures in real deployments. *(#435, #439)*
- API tests and their helpers are included in the CI type-checking gate. *(#440)*
- The contribution coverage map records implementation status, ownership and routing across
  lq-ai and lq-skills. *(#666)*

The release checklist now includes regenerating the committed OpenAPI export when the API
version changes, keeping its `info.version` aligned with the release metadata.

---

## Who built this release

| Contributor | What they landed |
|---|---|
| [@SaifAlYounan](https://github.com/SaifAlYounan) | property-based checks, synthetic PII measurement and API test type checking *(#435, #439, #440)* |
| [@chenzeyan54-commits](https://github.com/chenzeyan54-commits) | the nightly Cypress API address and CORS repair, with @houfu *(#630)* |
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | convergent OCR citation normalization *(#652)* |
| [@sergiomaldo](https://github.com/sergiomaldo) | the gateway timeout change, with @houfu *(#664)* |
| [@pscripps](https://github.com/pscripps) | the contribution coverage map *(#666)* |

Maintainer work by [@houfu](https://github.com/houfu) includes the required-input composer,
Ollama tool-call translation, gateway defaults and key handling, ingestion errors, autonomous
dispatch auditing, audit timestamps and MCP failure diagnostics.
*(#669, #649, #650, #660, #655, #656, #651, #659)*

---

## Schema

The API's Alembic head moves from **0068 to 0069**. Migration **0069** changes
`audit_log.timestamp`'s default from `now()` to `clock_timestamp()`, so future rows record
insertion time rather than transaction-start time. Existing rows retain their timestamps;
wall-clock time does not guarantee event order. Startup applies the migration. Do not run
host-side Alembic against the live stack. A downgrade restores the old default but does not
rewrite timestamps already recorded under 0069. *(#651)*

---

## Honest scope

The input form covers skills attached through the composer. Inputs for kept-on skills are still
lost when reopening a chat (DE-402), and the send-time slash fallback still supplies no inputs
(DE-403). Use a fresh chat and the skill picker to reach the form. The Enhance Prompt review
screen, per-input file selection and legacy flat input lists remain outside this fix (DE-010).

The phone-width layout remains a known limitation: at 390 × 844, side panes obscure the composer
and compress required fields. The desktop light-theme layout passed at 1280 × 900. LQ.AI supports
light theme only; the System setting resolves to light.

## 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.
