chore: commit remaining modified files from refactoring
This commit is contained in:
@@ -25,3 +25,8 @@ dummy
|
||||
|
||||
# Worktrees
|
||||
.worktrees/
|
||||
|
||||
# Generated analysis files
|
||||
thoughts/explorer/*.json
|
||||
thoughts/explorer/*_report.md
|
||||
thoughts/shared/analyses/
|
||||
|
||||
+74
-15
@@ -1,15 +1,74 @@
|
||||
# DO NOT EDIT - read-only until validated
|
||||
# Sanitized manifest: contains non-sensitive sample excerpts only
|
||||
files:
|
||||
- path: src/lib/schema.ts
|
||||
evidence_excerpt: "Defines schema for user input validation"
|
||||
flags:
|
||||
needs_review: true
|
||||
- path: src/api/handler.ts
|
||||
evidence_excerpt: "Handles API requests and routing"
|
||||
flags:
|
||||
needs_review: false
|
||||
- path: README.md
|
||||
evidence_excerpt: "Project overview and setup instructions"
|
||||
flags:
|
||||
needs_review: true
|
||||
name: stemwijzer
|
||||
version: 2
|
||||
description: Dutch political voting compass (Stemwijzer) - Mind Model constraints
|
||||
|
||||
categories:
|
||||
# Core documentation
|
||||
- path: system.md
|
||||
description: System overview and architecture summary
|
||||
group: docs
|
||||
- path: tech-stack.yaml
|
||||
description: Technology stack with versions and purposes
|
||||
group: docs
|
||||
- path: conventions.yaml
|
||||
description: Coding conventions and style guide
|
||||
group: docs
|
||||
- path: domain.yaml
|
||||
description: Domain entities, terms, and relationships
|
||||
group: docs
|
||||
|
||||
# Design patterns
|
||||
- path: patterns/architecture.yaml
|
||||
description: Repository, Facade, Pipeline architectural patterns
|
||||
group: patterns
|
||||
- path: patterns/python.yaml
|
||||
description: Python-specific patterns (Singleton, dataclass, context manager)
|
||||
group: patterns
|
||||
- path: patterns/database.yaml
|
||||
description: DuckDB connection patterns and ORM usage
|
||||
group: patterns
|
||||
- path: patterns/api.yaml
|
||||
description: API client patterns with retry logic and pagination
|
||||
group: patterns
|
||||
- path: patterns/streamlit.yaml
|
||||
description: Streamlit session state and page patterns
|
||||
group: patterns
|
||||
|
||||
# Coding constraints
|
||||
- path: constraints/error-handling.yaml
|
||||
description: Error handling patterns with safe fallbacks
|
||||
group: constraints
|
||||
- path: constraints/logging.yaml
|
||||
description: Logging conventions and best practices
|
||||
group: constraints
|
||||
- path: constraints/naming.yaml
|
||||
description: File, class, function naming rules
|
||||
group: constraints
|
||||
- path: constraints/imports.yaml
|
||||
description: Import organization and module structure
|
||||
group: constraints
|
||||
- path: constraints/types.yaml
|
||||
description: Type hint conventions
|
||||
group: constraints
|
||||
|
||||
# Code examples
|
||||
- path: examples/database-example.py
|
||||
description: MotionDatabase usage example
|
||||
group: examples
|
||||
- path: examples/api-client-example.py
|
||||
description: TweedeKamerAPI usage
|
||||
group: examples
|
||||
- path: examples/pipeline-example.py
|
||||
description: Pipeline phase example
|
||||
group: examples
|
||||
- path: examples/streamlit-page-example.py
|
||||
description: Streamlit page pattern
|
||||
group: examples
|
||||
|
||||
# Anti-patterns and workflows
|
||||
- path: anti-patterns.yaml
|
||||
description: Known anti-patterns to avoid
|
||||
group: meta
|
||||
- path: workflows.yaml
|
||||
description: Key workflows (VotingSession, DataIngestion, EmbeddingGeneration)
|
||||
group: meta
|
||||
|
||||
+66
-11
@@ -1,14 +1,69 @@
|
||||
# System Overview: Stemwijzer
|
||||
# System Overview
|
||||
|
||||
This mindmodel documents constraints, conventions and patterns for the Stemwijzer
|
||||
project (Python Streamlit app with DuckDB-backed pipeline for parliamentary
|
||||
motions embedding analysis).
|
||||
## Project: Stemwijzer (Dutch Political Voting Compass)
|
||||
|
||||
Key points:
|
||||
- Language: Python >=3.13
|
||||
- UI: Streamlit multi-page app (Home.py, pages/)
|
||||
- Storage: DuckDB with JSON fallback for tests/dev (database.py)
|
||||
- Pipeline: ETL and SVD/text fusion pipeline (pipeline/run_pipeline.py)
|
||||
- AI: ai_provider adapter uses HTTP-based OpenRouter/OpenAI-compatible API with retry/backoff and local fallback. QWEN via OpenRouter is the recommended path; prefer OPENROUTER_API_KEY with OPENAI_API_KEY as a fallback where applicable.
|
||||
**Purpose**: A web application that maps the Dutch Tweede Kamer (House of Representatives) based on real parliamentary votes, helping citizens discover which political party aligns best with their views.
|
||||
|
||||
Use the .mindmodel/ constraints files to guide code changes, CI, and onboarding.
|
||||
## Architecture Summary
|
||||
|
||||
### Data Flow
|
||||
```
|
||||
TweedeKamer OData API
|
||||
↓
|
||||
API Client (api_client.py)
|
||||
↓
|
||||
DuckDB Database (database.py)
|
||||
↓
|
||||
Pipeline Processing (pipeline/)
|
||||
├── fetch_mp_metadata # MP party + tenure
|
||||
├── extract_mp_votes # voting_results → mp_votes
|
||||
├── svd_pipeline # SVD on vote matrix + Procrustes
|
||||
├── text_pipeline # AI embeddings via OpenRouter
|
||||
└── fusion # Combine SVD + text vectors
|
||||
↓
|
||||
Streamlit Web App (app.py, pages/)
|
||||
├── Home.py # Landing page
|
||||
├── 1_Stemwijzer.py # Voting quiz
|
||||
└── 2_Explorer.py # Political compass explorer
|
||||
```
|
||||
|
||||
### Key Components
|
||||
|
||||
| Component | Purpose | File(s) |
|
||||
|-----------|---------|---------|
|
||||
| **Database** | Motion storage, MP votes, embeddings | `database.py` |
|
||||
| **API Client** | TweedeKamer OData API integration | `api_client.py` |
|
||||
| **AI Provider** | OpenRouter API for embeddings/summaries | `ai_provider.py` |
|
||||
| **Pipeline** | Orchestrated data processing | `pipeline/run_pipeline.py` |
|
||||
| **Analysis** | SVD, clustering, trajectory computation | `analysis/*.py` |
|
||||
| **Similarity** | Motion similarity search | `similarity/*.py` |
|
||||
| **Web App** | Streamlit UI | `app.py`, `pages/*.py` |
|
||||
|
||||
### Data Models
|
||||
|
||||
**Core Entities**:
|
||||
- `Motion`: Parliamentary motion with voting results
|
||||
- `MP` / `MPMetadata`: Member of Parliament with party/tenure
|
||||
- `MPVote`: Individual vote record (Voor/Tegen/Onthouden/Geen stem/Afwezig)
|
||||
- `Party`: Political party
|
||||
- `UserSession` / `UserVote`: Voting session tracking
|
||||
- `SVDVector`: Dimensionality-reduced vote vectors
|
||||
- `FusedEmbedding`: Combined SVD + text embedding
|
||||
- `SimilarityCache`: Pre-computed motion similarities
|
||||
|
||||
### Technical Decisions
|
||||
|
||||
1. **DuckDB over SQLite**: Chosen for OLAP performance with complex analytical queries
|
||||
2. **ibis ORM**: Database-agnostic query building (currently using DuckDB backend)
|
||||
3. **SVD + Procrustes**: Aligns voting vectors across time windows
|
||||
4. **UMAP for visualization**: Non-linear dimensionality reduction for compass display
|
||||
5. **OpenRouter API**: Abstraction layer for AI embeddings (currently using Qwen)
|
||||
6. **Module-level singletons**: `db = MotionDatabase()` pattern for shared state
|
||||
|
||||
### Key Conventions
|
||||
|
||||
- **DuckDB connections**: Short-lived per method, always close
|
||||
- **Error handling**: Catch `Exception`, return safe fallbacks (False/[]/None)
|
||||
- **Logging**: Use `logging.getLogger(__name__)` - avoid print()
|
||||
- **Type hints**: Required on public functions with typing module imports
|
||||
- **Config**: Dataclass `Config` in `config.py`, accessed as `from config import config`
|
||||
|
||||
+59
-45
@@ -1,69 +1,81 @@
|
||||
# ARCHITECTURE
|
||||
---
|
||||
title: ARCHITECTURE
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
- Small Python project that collects, stores and presents Dutch parliamentary motions (Tweede Kamer). Itingests votes (OData API or HTML scraping), stores motions in a DuckDB file, generates short humansummaries using an LLM client, and exposes a Streamlit UI for users to vote and view matching results.
|
||||
- Small Python project that collects, stores and presents Dutch parliamentary motions (Tweede Kamer). It ingests votes via OData API, stores motions in a DuckDB file, generates short human-readable summaries using an LLM client, and exposes a Streamlit UI for users to vote and view matching results.
|
||||
|
||||
## Tech stack
|
||||
|
||||
- Language: Python (single-project repository)
|
||||
- Data: DuckDB (file: data/motions.db), ibis used in a small utility (read.py)
|
||||
- Web / UI: Streamlit (app.py)
|
||||
- HTTP: requests
|
||||
- HTML parsing: BeautifulSoup (scraper.py)
|
||||
- Scheduling: schedule (scheduler.py)
|
||||
- LLM: QWEN (via OpenRouter) / OpenAI-compatible client (summarizer.py uses an OpenRouter/OpenAI-compatible client configured via config). Prefer QWEN via OpenRouter where possible.
|
||||
- Packaging: pyproject.toml present
|
||||
- Data: DuckDB (file: data/motions.db)
|
||||
- Web / UI: Streamlit (app.py, pages/)
|
||||
- HTTP: requests (ai_provider.py, api_client.py)
|
||||
- LLM: QWEN (via OpenRouter) / OpenAI-compatible client (ai_provider.py). Prefer QWEN via OpenRouter where possible.
|
||||
- Analysis: scipy (SVD), scikit-learn (clustering), umap-learn (dimensionality reduction)
|
||||
- Visualization: Plotly
|
||||
- Packaging: pyproject.toml
|
||||
|
||||
## Top-level layout (annotated)
|
||||
|
||||
./
|
||||
|
||||
- app.py — Streamlit UI, main UI flow and session handling (entrypoint for web)
|
||||
- main.py — minimal CLI entry / small script
|
||||
- app.py — Streamlit UI entrypoint (Home.py routing)
|
||||
- Home.py — Thin wrapper with minimal logic
|
||||
- database.py — MotionDatabase: DuckDB schema, insert/query/update, party-match calculations
|
||||
- api_client.py — TweedeKamerAPI: fetch OData voting records and group into motions
|
||||
- scraper.py — MotionScraper: HTML fallback scraper for motion pages
|
||||
- summarizer.py — MotionSummarizer: LLM integration to generate layman_explanation
|
||||
- scheduler.py — DataUpdateScheduler: initial historical loads + periodic scheduled updates
|
||||
- config.py — Config dataclass: central configuration (DATABASE_PATH, API/AI settings, constants)
|
||||
- read.py — small ibis + duckdb demonstration/utility
|
||||
- fix_database.py — script to recreate/reset DuckDB schema
|
||||
- reset.py / verify.py — small maintenance scripts that call into database module
|
||||
- test.py — ad-hoc test script (manual insert/verification)
|
||||
- data/ — data/motions.db (DuckDB file)
|
||||
- ai_provider.py — Lightweight HTTP wrapper around OpenRouter/OpenAI-style backends
|
||||
- explorer.py — Explorer page logic, tab routing, SVD visualization
|
||||
- explorer_helpers.py — Pure functions for chart builders, coordinate computation
|
||||
- data/ — data/motions.db (DuckDB file, ~18GB)
|
||||
- pyproject.toml — project metadata / dependencies
|
||||
- .env — environment variables (not printed here)
|
||||
|
||||
## Directory structure
|
||||
|
||||
- `pages/` — Streamlit pages: 1_Stemwijzer.py, 2_Explorer.py
|
||||
- `pipeline/` — Data ingestion pipelines: run_pipeline.py, svd_pipeline.py, text_pipeline.py
|
||||
- `analysis/` — SVD, clustering, trajectory, visualization modules
|
||||
- `similarity/` — Embedding-based similarity computation
|
||||
- `scripts/` — Utility scripts for data processing
|
||||
- `tests/` — Test suite using pytest
|
||||
- `migrations/` — SQL migration files
|
||||
|
||||
## Core components
|
||||
|
||||
- Streamlit UI (app.py)
|
||||
- Streamlit UI (app.py + pages/)
|
||||
- Presents the voting UI, reads filtered motions from database, creates sessions, writes user votes
|
||||
- Calls: database.get_filtered_motions(), database.create_session(), database.update_user_vote(),database.calculate_party_matches(), summarizer.update_motion_summaries()
|
||||
- Explorer page (explorer.py) provides SVD visualization and party trajectory analysis
|
||||
- Storage (database.py)
|
||||
- MotionDatabase encapsulates DuckDB schema creation and CRUD for motions and user sessions
|
||||
- Exposes a module-level instance `db = MotionDatabase()` used across the codebase
|
||||
- Key responsibilities: insert_motion, get_filtered_motions, create_session, update_user_vote,calculate_party_matches
|
||||
- Ingestion (api_client.py + scraper.py)
|
||||
- Key responsibilities: insert_motion, get_filtered_motions, create_session, update_user_vote, calculate_party_matches
|
||||
- Ingestion (api_client.py + pipeline/)
|
||||
- api_client.py fetches votes via Tweede Kamer OData API and groups records into motions
|
||||
- scraper.py is an HTML fallback that scrapes motion pages and extracts vote info
|
||||
- Both provide structured motion dicts consumed by database.insert_motion()
|
||||
- pipeline/ orchestrates the full ingestion and analysis workflow
|
||||
- Summarization (summarizer.py)
|
||||
- Wraps an OpenRouter/OpenAI-compatible client (QWEN via OpenRouter recommended) to produce short layman explanations and persists them to DB
|
||||
- Reads motions without layman_explanation and updates rows
|
||||
- Orchestration (scheduler.py)
|
||||
- Runs initial historical ingestion and schedules periodic updates (using schedule)
|
||||
- Calls API client and summarizer and writes to the database
|
||||
- Analysis (analysis/)
|
||||
- SVD decomposition of voting patterns
|
||||
- UMAP for visualization
|
||||
- Clustering for motion grouping
|
||||
- Trajectory computation for party movement over time
|
||||
|
||||
## Data flow (high level)
|
||||
|
||||
1. Ingestion
|
||||
- scheduler / manual run triggers TweedeKamerAPI.get_motions(...) or MotionScraper.run_scraping_job()
|
||||
- Pipeline triggers TweedeKamerAPI.get_motions(...)
|
||||
- Each produced motion dict is passed to MotionDatabase.insert_motion()
|
||||
- insert_motion writes to DuckDB (data/motions.db)
|
||||
2. Enrichment
|
||||
- summarizer.update_motion_summaries() reads motions lacking layman_explanation, calls the LLM client (OpenRouter/OpenAI-compatible client) and writes summary text back to the DB
|
||||
3. Presentation / Interaction
|
||||
- summarizer.update_motion_summaries() reads motions lacking layman_explanation, calls the LLM client and writes summary text back to the DB
|
||||
3. Analysis
|
||||
- pipeline/svd_pipeline.py computes SVD embeddings from vote matrix
|
||||
- Results stored in svd_vectors table for visualization
|
||||
4. Presentation / Interaction
|
||||
- app.py (Streamlit) queries motions via db.get_filtered_motions() and displays them
|
||||
- Users vote; app.py writes votes into the database via db.update_user_vote()
|
||||
- app.py calls db.calculate_party_matches() to compute match percentages for parties
|
||||
@@ -72,43 +84,45 @@
|
||||
|
||||
- Tweede Kamer OData API (api_client.py)
|
||||
- HTTP (requests)
|
||||
- HTML parsing (BeautifulSoup) used by scraper.py
|
||||
- DuckDB (database file at data/motions.db)
|
||||
- ibis (read.py demonstrates an ibis.duckdb connection)
|
||||
- Streamlit for UI
|
||||
- OpenRouter/OpenAI-compatible LLM client (summarizer.py) — configured with environment variables in config.py. Prefer using OPENROUTER_API_KEY with OPENAI_API_KEY as a fallback where appropriate.
|
||||
- OpenRouter/OpenAI-compatible LLM client (ai_provider.py) — configured with environment variables in config.py
|
||||
|
||||
## Configuration
|
||||
|
||||
- config.py: central Config dataclass. Observed keys / env variables referenced across the codebase include:
|
||||
- config.DATABASE_PATH (default "data/motions.db")
|
||||
- OPENROUTER_API_KEY / other OPENROUTER_* variables used by summarizer.py
|
||||
- OPENROUTER_API_KEY / other OPENROUTER_* variables used by ai_provider.py
|
||||
- QWEN_MODEL (or other model identifier) referenced in summarizer.py
|
||||
- API timeout / batch size constants
|
||||
- .env file present at repo root (do not commit secrets). See .env.example if present (none observed).
|
||||
- .env file present at repo root (do not commit secrets)
|
||||
- Packaging metadata: pyproject.toml
|
||||
|
||||
## Build, run & development notes
|
||||
|
||||
- Install dependencies via the project's Python packaging (pyproject.toml). There is no Dockerfile or CIworkflows detected in the repository.
|
||||
- Use uv add and uv run to manage the dependencies in this directory and run scripts
|
||||
- Streamlit app: run `uv run streamlit run app.py` from project root to start the UI (app.py is the intended web entrypoint).
|
||||
- Install dependencies via the project's Python packaging (pyproject.toml)
|
||||
- Use `uv add` and `uv run` to manage the dependencies in this directory and run scripts
|
||||
- Streamlit app: run `uv run streamlit run app.py` from project root to start the UI (app.py is the intended web entrypoint)
|
||||
- Never use pip directly!
|
||||
- Scheduler: run scheduler.run_once() (script or import) or run scheduler.run_scheduler() for periodic ingestion.
|
||||
- Run tests: `uv run pytest tests/`
|
||||
|
||||
## Tests
|
||||
|
||||
- There is no test suite using pytest / unittest. One ad-hoc script `test.py` exists for manual insert verification.
|
||||
- Test suite in `tests/` using pytest
|
||||
- Run with `uv run pytest tests/`
|
||||
|
||||
## Notes / caveats
|
||||
|
||||
- Project is synchronous (no async/await patterns detected). Many modules rely on module-level singletons(e.g., `db = MotionDatabase()`, `summarizer = MotionSummarizer()`, `scraper = MotionScraper()`).
|
||||
- Error handling frequently catches broad Exception and prints to stdout (see database.py, api_client.py,scraper.py). Logging is not centralized (print statements used).
|
||||
- Project is synchronous (no async/await patterns detected)
|
||||
- Many modules rely on module-level singletons (e.g., `db = MotionDatabase()`, `summarizer = MotionSummarizer()`)
|
||||
- Error handling frequently catches broad Exception and prints to stdout (see database.py, api_client.py)
|
||||
- Logging is not centralized (print statements used)
|
||||
|
||||
## Where to look first (for contributors)
|
||||
|
||||
- app.py — follow the UI flow and see how votes & sessions are used
|
||||
- app.py + pages/ — follow the UI flow and see how votes & sessions are used
|
||||
- database.py — core data model and calculations
|
||||
- explorer.py — SVD visualization and party analysis
|
||||
- api_client.py — OData ingestion logic
|
||||
- summarizer.py — LLM usage and environment variables
|
||||
- scheduler.py — how ingestion is orchestrated over time
|
||||
- pipeline/ — how ingestion and analysis is orchestrated
|
||||
|
||||
@@ -260,7 +260,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
parser.add_argument(
|
||||
"--window-size",
|
||||
choices=["quarterly", "annual"],
|
||||
default="quarterly",
|
||||
default="annual",
|
||||
help="Time window granularity",
|
||||
)
|
||||
parser.add_argument("--svd-k", type=int, default=50, help="SVD dimensions")
|
||||
|
||||
@@ -917,5 +917,408 @@
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-03-30T18:52:43.630069Z"
|
||||
},
|
||||
{
|
||||
"id": "35963a0d-c63f-4afe-95f6-5b5208e57d29",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-01T23:46:34.584639Z"
|
||||
},
|
||||
{
|
||||
"id": "e68dfe7f-e0d9-4384-914d-4007f89b8e29",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-01T23:46:37.561361Z"
|
||||
},
|
||||
{
|
||||
"id": "e0a791fd-108d-49eb-bb09-8d0428e52e69",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-01T23:46:37.604922Z"
|
||||
},
|
||||
{
|
||||
"id": "f276f1ad-dc32-46a3-a74d-aa6e8a372fca",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-01T23:55:13.967080Z"
|
||||
},
|
||||
{
|
||||
"id": "7dc7b020-6c39-43c3-8aa3-174d344f91a7",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-01T23:55:14.671187Z"
|
||||
},
|
||||
{
|
||||
"id": "ac7e74cc-3b49-48dd-b9f0-d112df40d5ef",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-01T23:55:14.699780Z"
|
||||
},
|
||||
{
|
||||
"id": "fa59ab8a-2bb7-4b71-a48c-138278966dfb",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-02T19:01:42.827310Z"
|
||||
},
|
||||
{
|
||||
"id": "009b293a-fec3-49de-8492-3af93d597af0",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-02T19:01:44.222780Z"
|
||||
},
|
||||
{
|
||||
"id": "2c31b5a9-5332-4bec-abc7-bce8a8c1f91a",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-02T19:01:44.267873Z"
|
||||
},
|
||||
{
|
||||
"id": "fcb47926-785a-49a8-b492-6ed0f837f91e",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-02T19:02:21.461896Z"
|
||||
},
|
||||
{
|
||||
"id": "c20946d2-153e-44c7-9b87-a75974c05b8f",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-02T19:02:22.721758Z"
|
||||
},
|
||||
{
|
||||
"id": "6f943c69-e340-40c9-8df5-9a69dc0176d4",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-02T19:02:22.781638Z"
|
||||
},
|
||||
{
|
||||
"id": "0b0c6aa3-777f-4d13-b445-0334ca79abbc",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-02T19:05:29.897839Z"
|
||||
},
|
||||
{
|
||||
"id": "3fb54286-4495-4b42-8819-92fb05036d9b",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-02T19:05:31.206251Z"
|
||||
},
|
||||
{
|
||||
"id": "93ebb7a9-4734-43a7-8e32-7e4531e8393f",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-02T19:05:31.267085Z"
|
||||
},
|
||||
{
|
||||
"id": "d2a9f12e-9dfd-4879-b50f-1fc7db6f78f6",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-02T19:05:45.130369Z"
|
||||
},
|
||||
{
|
||||
"id": "5d5d756e-85aa-485e-8961-f2f6d495ebd6",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-02T19:05:46.352702Z"
|
||||
},
|
||||
{
|
||||
"id": "c4c61d53-22b5-4669-9ff3-457c0c0d0367",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-02T19:05:46.424142Z"
|
||||
},
|
||||
{
|
||||
"id": "b2599219-407b-4ea8-865c-41f61119b76b",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-02T19:07:57.967977Z"
|
||||
},
|
||||
{
|
||||
"id": "553c5da0-3fd6-4751-8990-5b2598f5e356",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-02T19:07:59.154098Z"
|
||||
},
|
||||
{
|
||||
"id": "73dd2e11-4ec5-4aa2-9434-1511988ee2ae",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-02T19:07:59.196193Z"
|
||||
},
|
||||
{
|
||||
"id": "e3bab538-e5e4-49be-9cb9-80a2fca75658",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-02T19:08:15.084851Z"
|
||||
},
|
||||
{
|
||||
"id": "2688a143-6744-41b2-975f-c55fd7594df5",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-02T19:08:16.326930Z"
|
||||
},
|
||||
{
|
||||
"id": "b4249645-67ef-4902-908b-f4e4aa17a7a2",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-02T19:08:16.371816Z"
|
||||
},
|
||||
{
|
||||
"id": "c4d307fe-8363-4de7-86be-65b28b44105c",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-02T19:14:50.773665Z"
|
||||
},
|
||||
{
|
||||
"id": "aaa28b70-3af9-4b0b-bb5a-203367206a9f",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-02T19:14:52.080492Z"
|
||||
},
|
||||
{
|
||||
"id": "19dbbc73-2954-4045-a0d3-21189380e097",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-02T19:14:52.152262Z"
|
||||
},
|
||||
{
|
||||
"id": "025319c5-5fc0-46e3-8230-216a70b40ac6",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-02T19:22:21.697203Z"
|
||||
},
|
||||
{
|
||||
"id": "0a2623fb-66be-4b62-8a1c-33c7f248bbd9",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-02T19:22:22.950861Z"
|
||||
},
|
||||
{
|
||||
"id": "7efd721a-ca00-48c4-95e5-d45a609404f4",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-02T19:22:22.994655Z"
|
||||
},
|
||||
{
|
||||
"id": "d9506033-2fc0-4317-8dd8-a388655e087b",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-02T19:23:15.774659Z"
|
||||
},
|
||||
{
|
||||
"id": "9fda605d-8c05-45b1-a9d6-b27c0cccbc7c",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-02T19:23:16.993127Z"
|
||||
},
|
||||
{
|
||||
"id": "b0d9da81-4528-4d79-97ef-107ec4f207dc",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-02T19:23:17.038391Z"
|
||||
},
|
||||
{
|
||||
"id": "4378866d-023b-4bfb-a1d1-c012bb7f2f09",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-02T19:24:31.074547Z"
|
||||
},
|
||||
{
|
||||
"id": "b0b5c909-305d-4947-af1e-a3495aba0c39",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-02T19:24:32.344948Z"
|
||||
},
|
||||
{
|
||||
"id": "c408f4c6-c188-4d20-8f06-ae293efce45e",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-02T19:24:32.397774Z"
|
||||
},
|
||||
{
|
||||
"id": "e4f83fc7-12f1-4b08-8f65-48dc4335f2dd",
|
||||
"actor_id": null,
|
||||
"action": "embedding_failed",
|
||||
"target_type": "motion",
|
||||
"target_id": "99",
|
||||
"metadata": {
|
||||
"error": "RuntimeError(\"Simulated embedding failure for index 0: 'failing motion'\")"
|
||||
},
|
||||
"created_at": "2026-04-02T19:25:52.766542Z"
|
||||
},
|
||||
{
|
||||
"id": "3705c35f-f94f-4333-9c09-318e57ec6bc3",
|
||||
"actor_id": null,
|
||||
"action": "test_action",
|
||||
"target_type": "unit",
|
||||
"target_id": "u1",
|
||||
"metadata": {
|
||||
"k": 1
|
||||
},
|
||||
"created_at": "2026-04-02T19:25:54.130128Z"
|
||||
},
|
||||
{
|
||||
"id": "c83ce165-d7fa-437a-a99d-ba5ef50083ab",
|
||||
"actor_id": null,
|
||||
"action": "another_action",
|
||||
"target_type": "motion",
|
||||
"target_id": null,
|
||||
"metadata": {},
|
||||
"created_at": "2026-04-02T19:25:54.178825Z"
|
||||
}
|
||||
]
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user