docs/eval-scorer.md was notes-to-self for work already finished. It told the reader to
add a class to eval_harness.py that has been there for months, specified the author's
own GPU by model number, and carried escaped-markdown artifacts from a bad paste. The
feature is real and was used — 9 eval runs, 668 questions, 3536 judgments — so the fix
is documentation, not deletion.
It now explains what coverage scoring measures and why it is worth having alongside
the judge model: the judge catches claims a source contradicts, the cross-encoder
catches claims a source simply does not cover. Includes how to read the number, and
the query that finds the interesting cases — paragraphs the judge passed but the
scorer did not, which is where technically-defensible-but-misleading answers show up.
The scorer defaulted to port 8001, which is also the MCP server's default, so running
both meant one silently failed to bind. Moved to 8005 and documented.
SCORER_ENDPOINT is now in .env.example, and the README has a documentation index —
every file under docs/ was previously unreachable from anywhere in the repo.
recovery.sh migrated data out of ArangoDB. This project abandoned Arango before the
extraction, and no one cloning plenum has an Arango server to migrate from — it was
carried over by inertia.
scripts/deploy_debate_embeddings.sh and deploy_summary_embeddings.sh were one-off
rollout scripts for features whose columns are now part of the base schema, so a fresh
install already has them.
scripts/correct_arguments.py was a single corrective pass over a specific extraction
error made by a specific small model on Swedish speeches from 2002 onward. Not
reusable, and not something a new deployment should run.
_postgres/rename_map.py and scripts/generate_rename_migration.py produced the
Swedish-to-English migration. That migration is written, applied, and its rollback
verified; the generator has no remaining use and the map described a schema that no
longer exists.
Root __init__.py was empty and made the repository look like an importable package,
which it is not.
scripts/test_auth_e2e.py moved to tests/ — it is a test, and putting it in scripts/
implied it was an operational tool.
Kept deliberately: the eval harness and its analysis scripts, which are a documented
feature rather than leftovers, and the embed/summarise/debate pipeline scripts, which
any deployment needs after an ingest run.
providers.template.yaml was a Raycast AI template. It named Raycast in its comments
and used api_keys/abilities/context — none of which provider_registry.py reads, while
omitting user_api_key and server_api_key_env, which it requires. Anyone copying it
got a file the application ignored. Replaced with one matching the code, covering
vLLM, Ollama, OpenRouter, Berget, OpenAI and Gemini.
docs/SETUP.md is written to be executed rather than skimmed: what the four external
dependencies are and which are optional, how to choose between providers, and a
verification command after every step that calls the real thing. Chat and tool calling
are checked separately, because a model can hold a conversation perfectly and still
never call a tool — which in this project means confident answers with no sources, the
one failure mode that matters most here.
Embeddings get their own section because they are a separate endpoint from chat and
conflating the two is the most common setup mistake, and because the dimension is
load-bearing: changing the model means re-embedding the whole corpus.
Ends with a symptom/cause/fix table covering the traps found during the production
cutover — the EnvironmentFile parsing difference, app.fts_config not surviving a
restore, and .env being unsourceable in bash.
Verified: every verification block in the guide was run against the live deployment.
Site copy now resolves through CONTENT_DIR, alongside PARLIAMENT_CONFIG and
PROMPTS_DIR. All three let a deployment keep its own wording, branding and contact
details outside the repository, so they never appear in a diff against upstream —
which is what keeps a production fork mergeable.
parliament.yaml's site.title was "rixdagen.se". That is the deployment's identity,
not Sweden's data, so upstream now ships a neutral default. The Swedish user guide
keeps its content but loses the personal contact details and site-specific wording;
a deployment ships its own guide by pointing CONTENT_DIR at it.
Fixes /api/guide, which still read ../user-guide.md after that file moved to
content/sv/ and had been returning 404.
Deliberately kept: the author metadata in pyproject.toml and the copyright line in
LICENSE, which are attribution rather than configuration, and the README's note that
this runs in production as rixdagen.se, which is provenance worth stating.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
README, PORTING.md and SCHEMA.md all described Swedish column names that no longer
exist. SCHEMA.md is rewritten around the English names and now explains why the
awkward ones are what they are: speaker_name rather than speaker (English "Speaker"
is the presiding officer), session_label rather than term (the European Parliament
uses term for its five-year cycle), document_proposals for a concept English has no
single word for.
Also records two things learned while verifying the migration: pg_dump does not
capture database-level settings, so a restore silently loses app.fts_config and
searches come back empty with no error; and saved chat snapshots contain SQL written
against the old column names, which is why the rename cannot be a clean break.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AGPL-3.0-or-later, with a README note offering other terms on request for
newsrooms and public-interest projects.
README rewritten in English, replacing a 55 KB Swedish document that described a
Sweden-only tool. It states plainly what is and is not yet country-agnostic rather
than overselling: the schema still carries Swedish column names, and docs/SCHEMA.md
translates them until the rename lands.
docs/PORTING.md is the guide this whole effort exists for — what a Bulgarian, UK or
EU deployment actually has to write. It is honest about the parts that are real work
(the ingest adapter, data quality, the untranslated UI) and about the assumption
underneath the data model, so nobody invests in an adapter for a parliament that does
not fit.
SECURITY.md documents the database_query issue rather than leaving deployers to find
it, and gives the read-only role to run against. .env.example documents all 48
environment variables, which were previously discoverable only by grep.
CI runs ruff, applies schema.sql to a clean pgvector database, runs the tests, builds
the frontend, and scans for secrets. The schema step exists because that file drifted
from production once already. tsc is non-blocking until the nine inherited type
errors are fixed.
Makefile rewritten around a documented setup/dev/test/lint flow, and carries the
check-fork-divergence target the production fork uses to prove it differs from
upstream only under deploy/prod/.
Also removed the personal GitHub Copilot instructions file.
Verified: no secrets, no personal contact details, and no private IPs or hostnames
in shipped source; backend still imports.
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>