v3.11.3 — wiki entry summaries were generated as JSON (#285) #292

Merged
claude-bot merged 2 commits from fix/lore-summary-prose into main 2026-08-06 17:03:20 +00:00
Contributor

Supersedes v3.11.2, which was tagged but never deployed to production. The dev deploy caught this against a real LLM.

No migrations. BOT_CONTRACT_VERSION stays 1.

The bug

An approved wiki entry came out with a summary of {"proposals":[]}.

generate_structured_text defaults to json_mode=True with _LORE_PROPOSAL_SYSTEM_PROMPT. The summary task called it bare, so it asked the model for:

a 2-3 sentence summary… plain prose only — no headings or bullet points

…in the user prompt, while the system prompt simultaneously instructed it to emit lore proposals as JSON. The model followed the system prompt, and the result was stored verbatim as entry.summary.

Fixed by passing an explicit prose system prompt and json_mode=False, matching how the journal and lore-merge tasks already call the same transport.

Why this is release-blocking rather than a minor fix

The bug predates v3.11.2. But it was only ever reachable through the manual "regenerate summary" button, which is rarely used.

v3.11.2 (#285) made that generator run on every proposal approval. So a latent bug became a data-corrupting one: it would have written JSON into the summary of every entry a GM approves, at exactly the moment the feature started being useful.

Why the test suite missed it

Every test mocks at the generate_structured_text seam. They assert that the task is called and that its result is stored — never that the request asks for the right output format. No amount of the existing 880 tests would have caught this; it took a real model on a real deploy.

The new test closes that specific gap: it captures the transport kwargs and asserts both json_mode=False and a prose system prompt, plus that a stored summary never begins with a brace.

Production data

Checked, read-only: 46 lore entries, none with a summary at all. The generator had no automatic trigger before v3.11.2 and the manual button had evidently never been used, so there is nothing to repair.

On the version number

v3.11.2's tag and release are left in place rather than rewritten. Anything that already pulled that tag should get a version number that differs from the fixed code, not the same number with different contents.

Verification

  • Backend: 881 passed in 35.15s, full suite
  • ruff check + ruff format --check: clean, 194 files
  • scripts/check_version_sync.py: OK — app 3.11.3, bot contract v1
  • Dev deploy of v3.11.2 verified the other four fixes before this was found: #271 producing 3256 chars of context against real summaries, #287's failure base on all four lore tasks, #286's debounce key live in Redis, #285's task completing end-to-end

🤖 Generated with Claude Code

Supersedes v3.11.2, which was tagged but **never deployed to production**. The dev deploy caught this against a real LLM. No migrations. `BOT_CONTRACT_VERSION` stays 1. ## The bug An approved wiki entry came out with a summary of `{"proposals":[]}`. `generate_structured_text` defaults to `json_mode=True` with `_LORE_PROPOSAL_SYSTEM_PROMPT`. The summary task called it bare, so it asked the model for: > a 2-3 sentence summary… plain prose only — no headings or bullet points …in the *user* prompt, while the *system* prompt simultaneously instructed it to emit lore proposals as JSON. The model followed the system prompt, and the result was stored verbatim as `entry.summary`. Fixed by passing an explicit prose system prompt and `json_mode=False`, matching how the journal and lore-merge tasks already call the same transport. ## Why this is release-blocking rather than a minor fix The bug **predates v3.11.2**. But it was only ever reachable through the manual "regenerate summary" button, which is rarely used. v3.11.2 (#285) made that generator run on **every proposal approval**. So a latent bug became a data-corrupting one: it would have written JSON into the summary of every entry a GM approves, at exactly the moment the feature started being useful. ## Why the test suite missed it Every test mocks at the `generate_structured_text` seam. They assert *that* the task is called and *that* its result is stored — never that the request asks for the right output format. No amount of the existing 880 tests would have caught this; it took a real model on a real deploy. The new test closes that specific gap: it captures the transport kwargs and asserts both `json_mode=False` and a prose system prompt, plus that a stored summary never begins with a brace. ## Production data Checked, read-only: **46 lore entries, none with a summary at all.** The generator had no automatic trigger before v3.11.2 and the manual button had evidently never been used, so there is nothing to repair. ## On the version number v3.11.2's tag and release are left in place rather than rewritten. Anything that already pulled that tag should get a version number that *differs* from the fixed code, not the same number with different contents. ## Verification - Backend: **881 passed in 35.15s**, full suite - `ruff check` + `ruff format --check`: clean, 194 files - `scripts/check_version_sync.py`: OK — app 3.11.3, bot contract v1 - Dev deploy of v3.11.2 verified the other four fixes before this was found: #271 producing 3256 chars of context against real summaries, #287's failure base on all four lore tasks, #286's debounce key live in Redis, #285's task completing end-to-end 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Caught on the v3.11.2 dev deploy, against a real LLM: an approved wiki entry
came out with a summary of `{"proposals":[]}`.

`generate_structured_text` defaults to `json_mode=True` with
`_LORE_PROPOSAL_SYSTEM_PROMPT`. This task called it bare, so it asked the model
for "a 2-3 sentence summary… plain prose only — no headings or bullet points"
in the user prompt while the system prompt simultaneously instructed it to emit
lore proposals as JSON. The model followed the system prompt, and the result was
stored verbatim as entry.summary.

The bug predates this work, but it was only ever reachable through the manual
regenerate-summary button. #285 made the task run on every proposal approval,
which would have written JSON into the summary of every entry a GM approves —
so a latent bug became a data-corrupting one.

Now passes an explicit prose system prompt and json_mode=False, matching how the
journal (`_JOURNAL_SYSTEM_PROMPT`) and lore-merge (`_LORE_MERGE_SYSTEM_PROMPT`)
tasks already call the same transport.

Worth noting why the suite missed it: every test mocks at the
generate_structured_text seam, so they assert that the task is called and that
its result is stored, never that the request asks for the right output format.
The new test closes that specific gap — it captures the kwargs and asserts both
json_mode=False and a prose system prompt, plus that a stored summary never
begins with a brace.

Prod was checked and is unaffected: 46 lore entries, none with a summary at all,
so the manual button had never been used there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
chore(release): v3.11.3
All checks were successful
CI / Backend lint (ruff) (pull_request) Successful in 1m29s
CI / Bot/backend version sync (pull_request) Successful in 53s
CI / Frontend tests, audit, and build (pull_request) Successful in 3m3s
CI / Docker image build (pull_request) Successful in 42s
CI / Bot tests and audit (pull_request) Successful in 3m20s
CI / Backend migration, tests, and audit (pull_request) Successful in 7m22s
06257a1219
Supersedes v3.11.2, which was tagged but never deployed to production — the
dev deploy caught wiki entry summaries being generated as JSON rather than prose
(#285), and v3.11.2 is what made that generator run automatically.

APP_VERSION and BOT_EXPECTED_APP_VERSION move to 3.11.3 together.
BOT_CONTRACT_VERSION stays at 1. No migrations.

v3.11.2's tag and release are left in place rather than rewritten: anything that
already pulled that tag should get a version number that differs from the fixed
code, not the same one with different contents.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
claude-bot deleted branch fix/lore-summary-prose 2026-08-06 17:03:20 +00:00
Sign in to join this conversation.
No description provided.