schema.sql had drifted badly enough that a newcomer running it got a database the
code partly fails against. Missing entirely: error_log, llm_events, and the four
eval_* tables. Missing columns: talks.dok_id (written by every ingest run),
talks.summary_embedding, talks.arguments/arguments_corrected/tagging_failed,
debates.summary_embedding, and four chat_snapshots columns including llm_messages.
Six indexes were undocumented, among them both HNSW summary-embedding indexes.
Also removed `*.sql` from .gitignore in the previous commit, which is why 14 of the
16 migration files could be recovered at all.
This has to be right before the rename lands, since everything downstream treats
schema.sql as the definition of truth.
Verified by building a scratch database from schema.sql and diffing it against
production: 251 columns across 22 tables and all 66 indexes identical.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The project could only run from /home/lasse/riksdagen: 22 files hardcoded that
path, mostly as an `os.chdir(...)` + `sys.path.append(...)` prelude. Those now
derive the root from the file's own location via bootstrap.py, and bulk data
resolves against PLENUM_DATA_DIR.
requirements.txt was from March 2023 and listed Streamlit, altair and pydeck while
omitting fastapi, uvicorn, psycopg2 and pgvector. Replaced with a pyproject.toml
derived from the actual import graph, plus ruff and pytest config.
Postgres opened its connection pool in __init__, so `import backend.app` failed
outright without a reachable database — breaking test collection and any tooling
that merely imports the app. The pool is now opened on first use behind a lock.
systemd units and an nginx site move to deploy/examples/ with __PROJECT_ROOT__ and
__DOMAIN__ placeholders. Real values belong in the deployment's own deploy/prod/,
which is a path upstream never writes to, so the two cannot conflict on merge.
Removed: scripts/migrate_keys.py (an already-executed Arango migration referenced
nowhere) and a dead `import talks2db` in download_talks.py that pointed at a file
excluded from this repo.
Verified: `import backend.app` now succeeds with neither a database nor any network,
and all rewritten scripts import from a foreign working directory with their module
docstrings intact.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
_llm called env_manager.set_env() at import time, which connected to a private
ArangoDB to fetch secrets. That single line meant a fresh clone could not start,
regardless of what else was configured. Both packages also lived in separate
private repos and were gitignored here, so the code shipped without them.
packages/llm/ is 780 lines against _llm's 1750. Dropped as unused by this project
(measured, zero call sites): token counting and message trimming, image/vision
handling, make_summary, the ollama-specific paths, the query/user_input/context
argument style, and the self-mutating provider_quirks.json cache.
Kept and reworked:
- tools.py, the docstring -> JSON-schema tool registry, which has no equivalent
in the cuj-fup client and which llm_tools.py depends on entirely.
- The provider quirks that actually matter: vLLM-only extra_body fields stripped
for hosted providers, enable_thinking disabled at template level when think is
off, reasoning models (o1/o3/o4/gpt-5) switched to max_completion_tokens.
Adopted from cuj-fup's client: LLMConfig as a dataclass instead of 20 constructor
kwargs, the SDK's native max_retries instead of hand-rolled backoff, and error
messages that name the likely cause.
Fixes a latent bug: Optional[list[str]] parameters were advertised to the model as
strings, because get_origin(Optional[X]) is Union, so neither the schema mapping
nor the list coercion in execute_tool fired. `parties`, `people` and `focus_ids`
were all affected.
Also drops a dead SELECT-only guard in execute_tool that keyed on a parameter name
(`sql_query`) that no tool has ever used. Real SQL hardening is tracked separately.
Verified: `import backend.app` succeeds with all external network blocked and zero
outbound connection attempts; all 12 tools register; live vLLM calls confirmed for
plain generation, structured output via format=, tool execution, and the
error-returns-a-string contract that call sites branch on.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Seeded via an explicit allow-list (see /home/lasse/plenum-seed.sh) rather than by
deleting files from a copy, so nothing sensitive can survive by omission.
Excluded: WireGuard backup + client config, the plaintext DB password in admin.py,
Arango credentials in scripts/notes.md, .claude/settings.json, a 113 MB log,
providers.yaml (private endpoint), the Arango/ChromaDB-era scripts, the duplicated
claude-design-system frontend copy, and assorted screenshots and one-off planning docs.
297 tracked files / 49 MB of history -> 161 files / 2.1 MB.
Recovered 14 database migrations that the old .gitignore's `*.sql` rule had been
hiding from version control.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>