diff --git a/CHANGELOG.md b/CHANGELOG.md index 0477848..9109cbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,32 @@ may change in any release. See the status note in the README. ## [Unreleased] +## [0.5.7] — 2026-10-31 + +A maintenance release: dependency updates since 0.5.6, one security fix in the frontend, and a test flake fixed. +Nothing in the configuration, the API or the schema changes, and there is no new migration. The database image moves +to `pgvector/pgvector:0.8.7-pg18`, a patch release of the extension on the same Postgres major, so the data +directory and its mount stay as they are. + +### Changed + +- **Spring Boot 4.1.2, Gradle 9.8.2, bun 1.4.4, Testcontainers 2.0.5, Spotless 8.10.4, Vitest 5 with Angular 22.2**, + and the rest of the backend and frontend minor and patch updates. The frontend image builds on Node.js 24, and its + runtime is `nginx-unprivileged` 1.31. +- **The database image is `pgvector/pgvector:0.8.7-pg18`**, in Compose and for the tests alike; Renovate had moved + only the Compose file, so for a while the tests checked a different image than the one that ships. +- **`@angular-architects/ngrx-toolkit` is replaced by `@ngrx-toolkit/core`**, the package's new name from v22 on. +- **Spring AI stays at 2.0.1.** 2.0.2 brings an openai-java (from 4.66.0) whose stream close releases the transport + under an in-flight read, so stopping a turn or hitting its deadline no longer ends the model call. Renovate proposes + Spring AI in a pull request of its own from now on. + +### Fixed + +- **dompurify 3.4.17**, which closes three advisories on 3.4.16 and earlier (critical: `SAFE_FOR_TEMPLATES` bypass in + shadow roots; high: an `IN_PLACE` hook left event handlers armed; low: the SMIL `href` guard skipped for XHTML). +- **The suggestion prewarm tests no longer fail on a loaded runner.** The model stub counted a connection dropped + before its body as a request and handed it the next scripted reply. + ## [0.5.6] — 2026-10-13 The chat's model picker shows what each model costs and what the chat has spent, every turn records its tokens and @@ -1778,7 +1804,8 @@ Found while building the demo, all of them in paths only a container exercises: left six. - The shortlist card printed the description's Markdown syntax in its teaser. -[Unreleased]: https://github.com/codeministry/leadgen/compare/v0.5.6...HEAD +[Unreleased]: https://github.com/codeministry/leadgen/compare/v0.5.7...HEAD +[0.5.7]: https://github.com/codeministry/leadgen/releases/tag/v0.5.7 [0.5.6]: https://github.com/codeministry/leadgen/releases/tag/v0.5.6 [0.5.5]: https://github.com/codeministry/leadgen/releases/tag/v0.5.5 [0.5.4]: https://github.com/codeministry/leadgen/releases/tag/v0.5.4 diff --git a/CLAUDE.md b/CLAUDE.md index aec01db..6e071b4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -42,7 +42,7 @@ Violating one of these is expensive, and most of them fail silently. bulk-archive: these run against the live instance from the terminal or as direct SQL. A one-off admin task that leaves a commit behind has been done wrong, because the next release then carries a migration nobody asked for. -- **The database image is the pinned `pgvector/pgvector:0.8.6-pg18`, set in `docker-compose.yml` and `Databases.java` and nowhere else.** — reasoning in `docs/decisions/retrieval.md`. +- **The database image is the pinned `pgvector/pgvector:0.8.7-pg18`, set in `docker-compose.yml` and `Databases.java` and nowhere else.** — reasoning in `docs/decisions/retrieval.md`. - **Mount the database volume at `/var/lib/postgresql`, never `…/data`; a major bump moves tag, `PGDATA`, mount and data at once.** — reasoning in `docs/decisions/retrieval.md`. - **The vector column is 2000 wide, a wider vector is truncated at the seam, and thresholds move only after measuring with `docs/samples/measure_embeddings.ts`.** — reasoning in `docs/decisions/retrieval.md`. - **No CV tailoring.** Fixed PDFs in `config/documents/`, selected by the language diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index a5f2cf4..8abdc24 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -14,7 +14,7 @@ plugins { } group = "de.codeministry" -version = "0.5.6" +version = "0.5.7" /* * Java 25 through the toolchain rather than the ambient JDK: Gradle runs on diff --git a/backend/smoke/docker-compose.smoke.yml b/backend/smoke/docker-compose.smoke.yml index 6e50974..a2cd932 100644 --- a/backend/smoke/docker-compose.smoke.yml +++ b/backend/smoke/docker-compose.smoke.yml @@ -1,6 +1,6 @@ # The smoke stack, as an OVERLAY on `docker-compose.yml` and never as a file of its own. # -# `postgres` is inherited verbatim, which is the point: `pgvector/pgvector:0.8.6-pg18` is +# `postgres` is inherited verbatim, which is the point: `pgvector/pgvector:0.8.7-pg18` is # named in exactly two places in this repository and a third copy is a third thing to # forget on the next major. Run it as # diff --git a/backend/src/main/java/de/codeministry/leadgen/config/ConfigProperties.java b/backend/src/main/java/de/codeministry/leadgen/config/ConfigProperties.java index a0b9d9e..c64946e 100644 --- a/backend/src/main/java/de/codeministry/leadgen/config/ConfigProperties.java +++ b/backend/src/main/java/de/codeministry/leadgen/config/ConfigProperties.java @@ -57,7 +57,7 @@ public record ConfigProperties( // One home per default, read by the bound constructor and the hand-built one alike, so // the two cannot drift. `@DefaultValue` takes a compile-time constant, hence strings. - private static final String DEFAULT_VERSION = "0.5.6"; + private static final String DEFAULT_VERSION = "0.5.7"; private static final String DEFAULT_CONFIG_POLL_INTERVAL = "PT2S"; private static final String DEFAULT_SCORE_BATCH_POLL_INTERVAL = "PT5M"; private static final String DEFAULT_INGEST_CRON = "-"; diff --git a/backend/src/main/resources/application.yaml b/backend/src/main/resources/application.yaml index bed6041..3480181 100644 --- a/backend/src/main/resources/application.yaml +++ b/backend/src/main/resources/application.yaml @@ -25,7 +25,7 @@ spring: name: leadgen # What a client reads in the `initialize` result: the running build, from the one place # the build names itself (leadgen.version below). - version: ${LEADGEN_VERSION:0.5.6} + version: ${LEADGEN_VERSION:0.5.7} # STREAMABLE and not SSE: Spring AI 2.0 deprecates SSE, and Streamable HTTP is what # current MCP clients negotiate. protocol: STREAMABLE @@ -43,10 +43,10 @@ spring: # not have to exist — without it the defaults apply. leadgen: # What the header shows, and the only place the running build names itself. Without this - # line the default on ConfigProperties applies and every image reports 0.5.6 — + # line the default on ConfigProperties applies and every image reports 0.5.7 — # the Gradle version is not injected into the jar, and the Dockerfile copies libs/*.jar # by glob, so nothing else carries it either. The deploy sets it from the image tag. - version: ${LEADGEN_VERSION:0.5.6} + version: ${LEADGEN_VERSION:0.5.7} config-dir: ${LEADGEN_CONFIG_DIR:config} security: # Asserts that something outside this process decides who reaches the port, which is diff --git a/backend/src/test/java/de/codeministry/leadgen/Databases.java b/backend/src/test/java/de/codeministry/leadgen/Databases.java index a4fd1b7..38ef025 100644 --- a/backend/src/test/java/de/codeministry/leadgen/Databases.java +++ b/backend/src/test/java/de/codeministry/leadgen/Databases.java @@ -35,7 +35,7 @@ public final class Databases { * no target here that could miss it. The trap is written out beside the mount it applies * to. */ - public static final String IMAGE = "pgvector/pgvector:0.8.6-pg18"; + public static final String IMAGE = "pgvector/pgvector:0.8.7-pg18"; private Databases() {} diff --git a/backend/src/test/java/de/codeministry/leadgen/LeadGenerationApplicationTests.java b/backend/src/test/java/de/codeministry/leadgen/LeadGenerationApplicationTests.java index 7523ff3..54c0605 100644 --- a/backend/src/test/java/de/codeministry/leadgen/LeadGenerationApplicationTests.java +++ b/backend/src/test/java/de/codeministry/leadgen/LeadGenerationApplicationTests.java @@ -69,7 +69,7 @@ void flywayCreatedTheBaselineSchema() { @Test void theVectorExtensionIsThereAndTheColumnHasAWidth() { - // The image is the thing under test here. `pgvector/pgvector:0.8.6-pg18` is a plain + // The image is the thing under test here. `pgvector/pgvector:0.8.7-pg18` is a plain // postgres with the extension added, and on any image without it `V22` fails at startup // naming the extension rather than the image — which is a long way from the compose file // that actually decides it. diff --git a/backend/src/test/java/de/codeministry/leadgen/web/StatusControllerTest.java b/backend/src/test/java/de/codeministry/leadgen/web/StatusControllerTest.java index cd226f5..ba667c8 100644 --- a/backend/src/test/java/de/codeministry/leadgen/web/StatusControllerTest.java +++ b/backend/src/test/java/de/codeministry/leadgen/web/StatusControllerTest.java @@ -19,7 +19,7 @@ // into the `spring-boot-webmvc-test` module. The old import compiles against // Boot 3 and simply does not exist here. @WebMvcTest(StatusController.class) -@TestPropertySource(properties = {"spring.application.name=lead-generation", "leadgen.version=0.5.6"}) +@TestPropertySource(properties = {"spring.application.name=lead-generation", "leadgen.version=0.5.7"}) class StatusControllerTest { @Autowired @@ -30,6 +30,6 @@ void returnsApplicationNameAndVersion() { Assertions.assertThat(mvc.get().uri("/api/v1/status")) .hasStatusOk() .bodyJson() - .isEqualTo("{\"application\":\"lead-generation\",\"version\":\"0.5.6\"}"); + .isEqualTo("{\"application\":\"lead-generation\",\"version\":\"0.5.7\"}"); } } diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index f4f494f..7bb99dd 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -44,7 +44,7 @@ flowchart LR direction TB web["web
nginx serving the Angular build,
/api proxied to api:8080"] api["api
Spring Boot: the pipeline,
the REST API, the schedulers"] - db[("postgres
pgvector/pgvector:0.8.6-pg18")] + db[("postgres
pgvector/pgvector:0.8.7-pg18")] web --> api --> db end subgraph outside["outside the machine"] diff --git a/docs/decisions/native-image.md b/docs/decisions/native-image.md index ecdf5db..7efadff 100644 --- a/docs/decisions/native-image.md +++ b/docs/decisions/native-image.md @@ -168,7 +168,7 @@ healthy service. It is a bash script and a compose **overlay**, not a Gradle task and not a compose file of its own. Not a Gradle task because it runs a container on a runner and dragging the configuration cache and the toolchain into that buys nothing. An overlay because -`pgvector/pgvector:0.8.6-pg18` is named in exactly two places in this repository and a +`pgvector/pgvector:0.8.7-pg18` is named in exactly two places in this repository and a third copy is a third thing to forget on the next major — `postgres` is inherited verbatim and only GreenMail, WireMock and the service under test are added. That service is called `smoke-api` and not `api`, because `api` carries a `build:` block an overlay cannot remove diff --git a/docs/decisions/retrieval.md b/docs/decisions/retrieval.md index 661e4ce..732d668 100644 --- a/docs/decisions/retrieval.md +++ b/docs/decisions/retrieval.md @@ -429,7 +429,7 @@ test there was, and it was available at any point. ## Moved from the root CLAUDE.md -- **The database image is `pgvector/pgvector:0.8.6-pg18`, not plain postgres.** Deduplication's +- **The database image is `pgvector/pgvector:0.8.7-pg18`, not plain postgres.** Deduplication's two similarity strategies compare vectors, `V22` creates the extension, and an image without it fails that migration with an error naming the extension rather than the image. It is named in `docker-compose.yml` and once for the tests in diff --git a/frontend/package.json b/frontend/package.json index 5517f6d..8b83c12 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "frontend", - "version": "0.5.6", + "version": "0.5.7", "scripts": { "start": "ng serve", "build": "ng build", diff --git a/frontend/src/app/app.spec.ts b/frontend/src/app/app.spec.ts index 7cdb1b1..91bfe27 100644 --- a/frontend/src/app/app.spec.ts +++ b/frontend/src/app/app.spec.ts @@ -21,7 +21,7 @@ describe('App', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - httpMock.expectOne('/api/v1/status').flush({application: 'lead-generation', version: '0.5.6'}); + httpMock.expectOne('/api/v1/status').flush({application: 'lead-generation', version: '0.5.7'}); // Run ingest and the model choice left the header for the workflow screen (operator, // 2026-09-27), so the shell does not create the scoring-model store: the model list is // not asked for here. The ingest store is created at the root (fix 2F-5), so its @@ -34,7 +34,7 @@ describe('App', () => { await fixture.whenStable(); fixture.detectChanges(); - expect(fixture.nativeElement.textContent).toContain('lead-generation 0.5.6'); + expect(fixture.nativeElement.textContent).toContain('lead-generation 0.5.7'); httpMock.verify(); });