Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,22 @@ reasoning attached, in [docs/history/LESSONS_LEARNED.md](docs/history/LESSONS_LE

## [Unreleased]

**Upgrading.** A deployment that uses the cloud fallback must set `CLOUD_BASE_URL` (for
OpenAI, `https://api.openai.com/v1`) and drop any `provider/` prefix from `CLOUD_MODEL`.
`CLOUD_PROVIDER` is no longer read. No migrations.
## [3.6.0] — 2026-11-11

The release of the QP-9 review's open findings (QP-10): R-8 to R-12 and item 13 are fixed,
along with four found by the separate reviews of those fixes. It also replaces `litellm`
with a direct OpenAI-compatible client (QP-11, ADR-4). A minor rather than a patch, because
`main` carries that feature; see `CONTRIBUTING.md`.

**Upgrading from 3.5.0.**

- A deployment that uses the cloud fallback must set `CLOUD_BASE_URL` (for OpenAI,
`https://api.openai.com/v1`) and drop any `provider/` prefix from `CLOUD_MODEL`.
`CLOUD_PROVIDER` is no longer read.
- Migration 0024 (additive: `users.tokens_valid_after`) applies at startup.
- The image keeps the settings page's values and fine-tuned rerankers on a new `app_data`
volume. Values held in the old container are not carried over, so set them once more
after the upgrade (see Changed).

### Security

Expand All @@ -36,6 +49,14 @@ OpenAI, `https://api.openai.com/v1`) and drop any `provider/` prefix from `CLOUD
a chat narrowed to some documents searched the whole workspace whenever the planner
judged a question multi-hop (ADR-6 recorded it). Its citations also lacked the tier, so
a global contribution was cited as a workspace document. Workspace isolation itself held.
- **A global contribution is never mistaken for a document without a workspace.** Both have
no `workspace_id`, so an upload naming no workspace, an admin's workspace-less connector,
or the re-ingest worker could update a contribution in place, and every workspace reads
the tier. The worker also picked contributions as stale and tried to re-read a source
file they do not have. Found by the separate review of #528.
- **A workspace's ontology counts only its live documents.** `workspace_ontology` counted
the entities of retired documents, and of chunks a re-ingest had retired. Found by the
separate review of #527.

### Changed

Expand Down Expand Up @@ -70,20 +91,6 @@ OpenAI, `https://api.openai.com/v1`) and drop any `provider/` prefix from `CLOUD
also counted deactivated admins, so the last active one could be deactivated while a
deactivated one existed; it now counts active admins.

### Fixed

- **A global contribution is never mistaken for a document without a workspace.** Both have
no `workspace_id`, so an upload naming no workspace, an admin's workspace-less connector,
or the re-ingest worker could update a contribution in place, and every workspace reads
the tier. The worker also picked contributions as stale and tried to re-read a source
file they do not have. Found by the separate review of #528.

### Fixed

- **A workspace's ontology counts only its live documents.** `workspace_ontology` counted
the entities of retired documents, and of chunks a re-ingest had retired. Found by the
separate review of #527.

## [3.5.0] — 2026-10-31

The release that closes the quality plan's maturity target (Initiative 12). All six
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ services:
environment:
# ── Application ──────────────────────────────────────
APP_ENV: ${APP_ENV:-production}
APP_VERSION: ${APP_VERSION:-3.5.0}
APP_VERSION: ${APP_VERSION:-3.6.0}
SECRET_KEY: ${SECRET_KEY:?SECRET_KEY must be set}
JWT_SECRET_KEY: ${JWT_SECRET_KEY:?JWT_SECRET_KEY must be set}
ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD must be set}
Expand Down
4 changes: 2 additions & 2 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ to empty, in which case the router falls back to the active model.

| Variable | Default | Effect |
|---|---|---|
| `APP_VERSION` | `3.5.0` | Reported as `system.app_version` by `GET /api/settings/stats` (admin). See the note below |
| `APP_VERSION` | `3.6.0` | Reported as `system.app_version` by `GET /api/settings/stats` (admin). See the note below |
| `STATE_FILE` | `app_state.json` (host-run); `/app/data/app_state.json` (image) | Where the settings page persists the active model and RAG parameters. In compose it lives on the `app_data` volume |
| `MAX_CONTENT_LENGTH` | `16777216` | Upload ceiling in bytes (16 MB), enforced while the upload streams to disk |
| `UVICORN_WORKERS` | `1` | Worker processes. **Only `1` is supported** — the app refuses to boot otherwise |
Expand Down Expand Up @@ -494,5 +494,5 @@ to empty, in which case the router falls back to the active model.
> **That is not hypothetical — it is what happened.** Until 2026-08-31 the three read
> `1.0.0`, `0.5.0` and `1.0.0` against a `v3.0.0-beta.1` tag: a containerised deployment
> reported **0.5.0**, a host-run one **1.0.0**, and neither was the version being run.
> All three now read `3.5.0`, and `tests/unit/test_app_version_is_consistent.py` fails if
> All three now read `3.6.0`, and `tests/unit/test_app_version_is_consistent.py` fails if
> they diverge again — the drift was silent precisely because no check compared them.
2 changes: 1 addition & 1 deletion docs/DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ attestations: an SPDX SBOM made by syft, and SLSA build provenance. All three na
image's digest, not a tag. Verify before you deploy a pulled image (QP-8):

```bash
IMAGE=ghcr.io/jwvanderstam/localchat:3.5.0
IMAGE=ghcr.io/jwvanderstam/localchat:3.6.0

# The signature: made by this repository's publish workflow, on main or a release tag
cosign verify "$IMAGE" \
Expand Down
4 changes: 2 additions & 2 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -1915,7 +1915,7 @@ start **before** QP-4's first PR.
> not on the strict mypy list. They were typed and added on 2026-10-31, with a test that
> keeps every service and repository on it.

#### QP-10 — The review's open findings ⬜ (after v3.4.0)
#### QP-10 — The review's open findings ✅ (done 2026-11-11, released as v3.6.0)

From `SECURITY.md`'s QP-9 register, in this order:

Expand Down Expand Up @@ -2055,7 +2055,7 @@ the generation path is a deterministic pipeline unless an answer-level eval says
| 24 | GKB-3 (chat reads the global tier) ✅ #467 + QP-3 (ratchets, ADR-7, PC-4) ✅ #468 + QP-6 (honest coverage, 85.68%) ✅ #469 + QP-7 e2e, 8 paths ✅ | ~1 week (weeks 3-4) |
| 25-27 | QP-4 (one aggregate per PR; CONN-1 decided before connectors) ✅ alongside QP-7 + QP-8 | ~12 days (weeks 4-9) |
| 28 | QP-5 (scope every path, compose `DocumentProcessor`; `Database` stays) ✅ + QP-9 (agent review) ✅ -> **v3.4.0** (the review's fixes); the re-audit moves to **v3.5.0**, once QP-7's required checks and QP-8's signed images hold | ~1 week (weeks 10-12) |
| 29 | QP-8's signed images ✅ + strict typing on every service ✅ -> **v3.5.0** ✅ 2026-10-31, re-audit; then QP-10 (R-8 ✅ #521) and QP-11 ✅ #523 | ~1 week |
| 29 | QP-8's signed images ✅ + strict typing on every service ✅ -> **v3.5.0** ✅ 2026-10-31, re-audit; then QP-10 ✅ (#521, #524-#529) and QP-11 ✅ #523 -> **v3.6.0** | ~1 week |
| — | Initiative 13 (RF-1..RF-5, retrieval flexibility) — future work, unscheduled by decision (2026-10-23; RF-5 added 2026-10-30) | — |
| **Total** | | **~22 weeks** (PG-0..PG-8 complete; it no longer gates Sprints 8-14. Sprints 15–18 are the audit's P2 tier, ordered cheapest-first rather than by the plan's driver ranking; reorder if GKB-1 wants P2-3's numbers first. **Execution order is not sprint-number order:** 15 to 21 run first, then 8 to 14. Sprints 19 to 21 are Initiative 11, placed directly after the P2 tier on 2026-09-26) |

Expand Down
2 changes: 1 addition & 1 deletion src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ def _production_errors(errors: list[str]) -> None:
# Bump on release, together with docker-compose.yml's default and the row in
# docs/CONFIGURATION.md — tests/unit/test_app_version_is_consistent.py holds the
# three together, because they had already drifted to 1.0.0, 0.5.0 and 1.0.0.
APP_VERSION: str = os.environ.get('APP_VERSION', '3.5.0')
APP_VERSION: str = os.environ.get('APP_VERSION', '3.6.0')

# Supported file types
SUPPORTED_IMAGE_EXTENSIONS: list[str] = ['.png', '.jpg', '.jpeg', '.gif', '.webp']
Expand Down
Loading