diff --git a/CHANGELOG.md b/CHANGELOG.md
index fbdf810f..ef74d1a8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,17 @@
# Changelog
+## Sprint 215 Grounded assistant cross-domain reliability (2026-07-16)
+
+- Raised the bounded local Ollama answer budget from 700 to 1,200 tokens after
+ a live Mol profile exhausted the smaller limit; `done_reason=length` remains
+ a hard error and incomplete text is still never returned.
+- Required listed themes to be covered without adding unrelated themes and
+ kept cross-domain answers compact without weakening source, unit, estimate,
+ chronology or unsupported-metric rules.
+- Exposed the output limit in the Unraid DockerMan template and aligned all
+ Compose, runtime, example and operator documentation defaults.
+
## Sprint 213-214 Cross-domain area profile (2026-07-16)
- Implemented one allowlisted MercatorNet WCS registry for official Flemish
diff --git a/backend/README.md b/backend/README.md
index dc28c5df..9d320bcb 100644
--- a/backend/README.md
+++ b/backend/README.md
@@ -1114,7 +1114,7 @@ OLLAMA_ENABLED=true
OLLAMA_BASE_URL=http://host.docker.internal:11434
OLLAMA_DEFAULT_MODEL=qwen3.5:9b
OLLAMA_TIMEOUT_SECONDS=120
-OLLAMA_MAX_OUTPUT_TOKENS=700
+OLLAMA_MAX_OUTPUT_TOKENS=1200
OLLAMA_CONTEXT_TOKENS=16384
```
@@ -1125,7 +1125,9 @@ models with `GET /api/v1/assistant/models` and ask a grounded question through
present in Ollama `/api/tags`. Missing water depth/bathymetry remains explicit;
the assistant cannot turn 2D water geometry into volume. GeoIntel rejects an
answer when Ollama reports `done_reason=length`, so a visibly truncated sentence
-is never presented as a complete result.
+is never presented as a complete result. The 1,200-token default leaves enough
+room for a compact cross-domain profile while the system prompt requires every
+explicitly requested theme and excludes unrelated themes.
## Agricultural-use parcel history
diff --git a/backend/app/core/config.py b/backend/app/core/config.py
index 24e258d4..b33e9a87 100644
--- a/backend/app/core/config.py
+++ b/backend/app/core/config.py
@@ -82,7 +82,7 @@ class Settings(BaseSettings):
ollama_base_url: str = Field(default="http://127.0.0.1:11434", validation_alias="OLLAMA_BASE_URL")
ollama_default_model: str = Field(default="qwen3.5:9b", validation_alias="OLLAMA_DEFAULT_MODEL")
ollama_timeout_seconds: int = Field(default=120, ge=5, le=600, validation_alias="OLLAMA_TIMEOUT_SECONDS")
- ollama_max_output_tokens: int = Field(default=700, ge=100, le=4_000, validation_alias="OLLAMA_MAX_OUTPUT_TOKENS")
+ ollama_max_output_tokens: int = Field(default=1_200, ge=100, le=4_000, validation_alias="OLLAMA_MAX_OUTPUT_TOKENS")
ollama_context_tokens: int = Field(default=16_384, ge=4_096, le=131_072, validation_alias="OLLAMA_CONTEXT_TOKENS")
cors_origins: list[str] | str = Field(
default=["http://localhost:5173", "http://127.0.0.1:5173"],
diff --git a/backend/app/services/geo_assistant_service.py b/backend/app/services/geo_assistant_service.py
index 36a328e7..8ee45cc4 100644
--- a/backend/app/services/geo_assistant_service.py
+++ b/backend/app/services/geo_assistant_service.py
@@ -525,6 +525,8 @@ class GeoAssistantService:
"Noem bij cijfers de bron en eenheid. Maak duidelijk onderscheid tussen exacte metingen en schattingen. "
"Als is_estimate true is, noem de waarde verplicht een schatting en nooit exact. "
"Objectaantallen zijn ondersteunend; geef betekenisvolle oppervlakte-, lengte- of bevolkingsmetriek voorrang. "
+ "Wanneer de gebruiker meerdere thema's opsomt, behandel elk gevraagd thema en voeg geen ongevraagd thema toe. "
+ "Houd het antwoord beknopt: groepeer de kernmetrieken per gevraagd thema en herhaal geen beperkingen. "
"Beschrijf alleen waargenomen verschillen; verzin geen oorzaak, voorspelling, verzadiging of andere verklaring. "
"Neem waarden en jaren letterlijk over en bereken zelf geen gemiddelde, tempo, oorzaak of afgeleide trend. "
"Gebruik platte tekst met korte alinea's en opsommingen, zonder Markdown-symbolen. "
diff --git a/backend/tests/test_sprint202_temporal_metrics_and_ollama.py b/backend/tests/test_sprint202_temporal_metrics_and_ollama.py
index 525597fa..ff0bd41f 100644
--- a/backend/tests/test_sprint202_temporal_metrics_and_ollama.py
+++ b/backend/tests/test_sprint202_temporal_metrics_and_ollama.py
@@ -202,12 +202,15 @@ def test_geo_assistant_sends_grounded_context_without_thinking_trace(monkeypatch
assert captured["payload"]["think"] is False
assert captured["payload"]["options"]["temperature"] == 0.0
assert captured["payload"]["options"]["num_ctx"] == 16_384
+ assert captured["payload"]["options"]["num_predict"] == 1_200
assert "Gebruik uitsluitend feiten en cijfers uit CONTEXT_JSON" in captured["payload"]["messages"][0]["content"]
assert "scope.label is het exact geanalyseerde gebied" in captured["payload"]["messages"][0]["content"]
assert "noem de waarde verplicht een schatting" in captured["payload"]["messages"][0]["content"]
assert "verzin geen oorzaak, voorspelling, verzadiging" in captured["payload"]["messages"][0]["content"]
assert "bereken zelf geen gemiddelde, tempo, oorzaak of afgeleide trend" in captured["payload"]["messages"][0]["content"]
assert "zonder Markdown-symbolen" in captured["payload"]["messages"][0]["content"]
+ assert "behandel elk gevraagd thema en voeg geen ongevraagd thema toe" in captured["payload"]["messages"][0]["content"]
+ assert "Houd het antwoord beknopt" in captured["payload"]["messages"][0]["content"]
assert "water_volume_available" in captured["payload"]["messages"][0]["content"]
@@ -254,6 +257,9 @@ def test_unraid_ollama_context_window_is_configurable() -> None:
assert "OLLAMA_CONTEXT_TOKENS: ${OLLAMA_CONTEXT_TOKENS:-16384}" in compose
assert 'Target="OLLAMA_CONTEXT_TOKENS"' in template
assert "OLLAMA_CONTEXT_TOKENS=16384" in env_example
+ assert "OLLAMA_MAX_OUTPUT_TOKENS: ${OLLAMA_MAX_OUTPUT_TOKENS:-1200}" in compose
+ assert 'Target="OLLAMA_MAX_OUTPUT_TOKENS"' in template
+ assert "OLLAMA_MAX_OUTPUT_TOKENS=1200" in env_example
def test_temporal_comparison_preserves_all_compatible_semantic_metrics() -> None:
diff --git a/deploy/unraid/README.md b/deploy/unraid/README.md
index c442ddfe..574a9fde 100644
--- a/deploy/unraid/README.md
+++ b/deploy/unraid/README.md
@@ -200,7 +200,7 @@ OLLAMA_ENABLED=true
OLLAMA_BASE_URL=http://host.docker.internal:11434
OLLAMA_DEFAULT_MODEL=qwen3.5:9b
OLLAMA_TIMEOUT_SECONDS=120
-OLLAMA_MAX_OUTPUT_TOKENS=700
+OLLAMA_MAX_OUTPUT_TOKENS=1200
OLLAMA_CONTEXT_TOKENS=16384
```
diff --git a/deploy/unraid/geointel-unraid-template.xml b/deploy/unraid/geointel-unraid-template.xml
index 62168241..8600f1b5 100644
--- a/deploy/unraid/geointel-unraid-template.xml
+++ b/deploy/unraid/geointel-unraid-template.xml
@@ -51,5 +51,6 @@
http://host.docker.internal:11434
qwen3.5:9b
120
+ 1200
16384
diff --git a/deploy/unraid/geointel.env.example b/deploy/unraid/geointel.env.example
index 3a01072f..226a9192 100644
--- a/deploy/unraid/geointel.env.example
+++ b/deploy/unraid/geointel.env.example
@@ -71,5 +71,5 @@ OLLAMA_ENABLED=true
OLLAMA_BASE_URL=http://host.docker.internal:11434
OLLAMA_DEFAULT_MODEL=qwen3.5:9b
OLLAMA_TIMEOUT_SECONDS=120
-OLLAMA_MAX_OUTPUT_TOKENS=700
+OLLAMA_MAX_OUTPUT_TOKENS=1200
OLLAMA_CONTEXT_TOKENS=16384
diff --git a/deploy/unraid/run-dockerman-container.sh b/deploy/unraid/run-dockerman-container.sh
index f70695b8..9e61ec1c 100644
--- a/deploy/unraid/run-dockerman-container.sh
+++ b/deploy/unraid/run-dockerman-container.sh
@@ -67,7 +67,7 @@ OLLAMA_ENABLED="${OLLAMA_ENABLED:-true}"
OLLAMA_BASE_URL="${OLLAMA_BASE_URL:-http://host.docker.internal:11434}"
OLLAMA_DEFAULT_MODEL="${OLLAMA_DEFAULT_MODEL:-qwen3.5:9b}"
OLLAMA_TIMEOUT_SECONDS="${OLLAMA_TIMEOUT_SECONDS:-120}"
-OLLAMA_MAX_OUTPUT_TOKENS="${OLLAMA_MAX_OUTPUT_TOKENS:-700}"
+OLLAMA_MAX_OUTPUT_TOKENS="${OLLAMA_MAX_OUTPUT_TOKENS:-1200}"
OLLAMA_CONTEXT_TOKENS="${OLLAMA_CONTEXT_TOKENS:-16384}"
install_dockerman_metadata() {
diff --git a/docker-compose.unraid.yml b/docker-compose.unraid.yml
index 342eff25..ac820c14 100644
--- a/docker-compose.unraid.yml
+++ b/docker-compose.unraid.yml
@@ -65,7 +65,7 @@ services:
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://host.docker.internal:11434}
OLLAMA_DEFAULT_MODEL: ${OLLAMA_DEFAULT_MODEL:-qwen3.5:9b}
OLLAMA_TIMEOUT_SECONDS: ${OLLAMA_TIMEOUT_SECONDS:-120}
- OLLAMA_MAX_OUTPUT_TOKENS: ${OLLAMA_MAX_OUTPUT_TOKENS:-700}
+ OLLAMA_MAX_OUTPUT_TOKENS: ${OLLAMA_MAX_OUTPUT_TOKENS:-1200}
OLLAMA_CONTEXT_TOKENS: ${OLLAMA_CONTEXT_TOKENS:-16384}
ports:
- "${GEOINTEL_FRONTEND_PORT:-1202}:80"
diff --git a/docker-compose.yml b/docker-compose.yml
index 64879ad8..f4eb2071 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -70,7 +70,7 @@ services:
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://host.docker.internal:11434}
OLLAMA_DEFAULT_MODEL: ${OLLAMA_DEFAULT_MODEL:-qwen3.5:9b}
OLLAMA_TIMEOUT_SECONDS: ${OLLAMA_TIMEOUT_SECONDS:-120}
- OLLAMA_MAX_OUTPUT_TOKENS: ${OLLAMA_MAX_OUTPUT_TOKENS:-700}
+ OLLAMA_MAX_OUTPUT_TOKENS: ${OLLAMA_MAX_OUTPUT_TOKENS:-1200}
OLLAMA_CONTEXT_TOKENS: ${OLLAMA_CONTEXT_TOKENS:-16384}
ports:
- "${GEOINTEL_BACKEND_PORT:-8000}:8000"
diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md
index 73ae4997..bcef9dad 100644
--- a/docs/CODEX_EXECUTION_LOG.md
+++ b/docs/CODEX_EXECUTION_LOG.md
@@ -1,3 +1,29 @@
+## Sprint 215 Grounded assistant cross-domain reliability (2026-07-16)
+
+Changed:
+- Measured the exact live Mol assistant context at 12 current themes, 36
+ semantic metrics, six temporal series and 17,302 compact JSON characters.
+- Increased the bounded output allowance to 1,200 tokens and instructed the
+ local model to cover every explicitly listed theme, omit unrelated themes
+ and avoid repeated limitations.
+- Kept `think=false`, deterministic temperature, the 16,384-token context and
+ fail-closed rejection of `done_reason=length` unchanged.
+- Added the output limit to the editable Unraid template and aligned all
+ deployment defaults and documentation.
+
+Validation evidence:
+- A read-only live production-chain probe with the 1,200-token setting
+ completed without truncation against the full persisted Mol context.
+- The focused assistant suite passed 14 tests.
+- The complete readiness gate passed 713 backend tests, backend compilation,
+ 105 documented API routes with three explicit binary/non-envelope routes,
+ one Alembic head and the frontend TypeScript and production build.
+- Tower deployment and browser verification follow in this pass.
+
+Next:
+- Deploy, rerun the exact six-theme Dutch question and verify the end-user
+ response and responsive assistant UI in the browser.
+
## Sprint 213-214 Cross-domain thematic rasters and DOV soil map (2026-07-16)
Changed: