From a03e015f0703fd25495fa202a7cefdf69ac41729 Mon Sep 17 00:00:00 2001 From: jwvanderstam Date: Wed, 11 Nov 2026 08:32:56 +0100 Subject: [PATCH] =?UTF-8?q?chore(release):=20v3.6.0=20=E2=80=94=20the=20QP?= =?UTF-8?q?-9=20review's=20open=20findings=20(QP-10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CHANGELOG: [Unreleased] becomes [3.6.0] — 2026-11-11, with a summary and an upgrade note. The note said "No migrations"; #524 added 0024 since, so it now names it, and it carries R-11's settings re-entry beside the cloud fallback's CLOUD_BASE_URL. The three "Fixed" headings the PRs appended are one section. - APP_VERSION 3.6.0 in src/config.py, docker-compose.yml and CONFIGURATION.md, and the image tag in DEPLOYMENT.md's verification example. - ROADMAP: QP-10 done; Sprint 29's row. A minor, not a patch: main carries QP-11's feature, and CONTRIBUTING makes the security release the next minor in that case. The security-release clock started with R-8 on 2026-11-07, so this is due by 2026-11-14. The tag is set by hand after this merges. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 41 ++++++++++++++++++++++++----------------- docker-compose.yml | 2 +- docs/CONFIGURATION.md | 4 ++-- docs/DEPLOYMENT.md | 2 +- docs/ROADMAP.md | 4 ++-- src/config.py | 2 +- 6 files changed, 31 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec0756b9..73bca45b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 @@ -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 @@ -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 diff --git a/docker-compose.yml b/docker-compose.yml index 35753b48..335c4679 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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} diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index a8cbe35e..0733cf03 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -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 | @@ -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. diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index c526c26e..41956bad 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -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" \ diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 613bc8a6..18a44dc4 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -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: @@ -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) | diff --git a/src/config.py b/src/config.py index c113b181..b52dc41b 100644 --- a/src/config.py +++ b/src/config.py @@ -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']