For Agents
Living index of themes for this project. Each H2 is a topic; bullets are wikilinks to related notes. Updated by
obsidian-documenterwhen documenting work. Read byhistorianat bootstrap. Topics kept alphabetical.
Architecture & Decisions
- dionysus — project overview, deployable units, latency-first design, v2 reframe
- dionysus-architecture-decisions — the ten decisions + the WHY behind each; “What changed in v2” diff
- dionysus-phase1-ingest-skeleton — Phase 1 code structure (2 crates:
dionysus-core+dionysus-ingest); the decisions realized in code
Backtest-Safety & Bitemporal Model
- dionysus — backtest-safety section (two time axes,
as_of, why-retrofit-is-brutal) - dionysus-architecture-decisions — decision 10: bitemporal from day 1 (the existential look-ahead-bias fix)
- dionysus-phase1-ingest-skeleton — bitemporal single knowledge-clock realized:
first_seen_at DEFAULT transaction_timestamp()read back in-tx → outboxknowledge_ts - dionysus-phase2-findings — drafted Phase 2 plan has a bitemporal clock SPLIT to fix: Qdrant payload
knowledge_ts = Utc::now()(line 1635) vs Postgrestransaction_timestamp()(line 1664) — different instants for the same enrichment, breaksas_ofparity between vector store and source of truth
Consistency & Messaging
- dionysus-architecture-decisions — transactional outbox (closes the dual-write gap); per-event
Nats-Msg-Id; NATS JetStream subject design + terminalnews.failed - dionysus-phase1-ingest-skeleton — outbox + single-leader relay built (
FOR UPDATE SKIP LOCKED); async-nats 0.49 double-await gotcha; post-build audit: relay must DRAIN-TO-EMPTY per cycle (one batch/cycle = unbounded backlog — HIGH prod bug,1204→100→1749→1749); NATS subject-injection slug (subject_token()) - dionysus-phase2-findings — drafted Phase 2 enricher bugs (fix on execution):
news.enrichedemitted even when confirm-searchable fails (onlywarn!, violates spec §8); unbounded retry storm (status IN ('detected','failed'), no attempt_count/terminal stop); rows stranded inenrichingon error/crash (no sweeper/lease reclaim)
Cost
- dionysus-architecture-decisions — ~765/mo Phase-2 VM; embeddings cheap, the VM is the recurring cost
Data & Ingestion
- dionysus-architecture-decisions — GDELT-spine hybrid + tiered full-text (live + CC-NEWS), filtered v1 corpus, fast/slow path; durable GDELT gotchas (scale, raw entities, format/license)
- dionysus-phase1-ingest-skeleton — GKG 2.1 parser with empirically-verified column indices; frozen canonical-URL rule (percent-encoding equivalence); live-smoke-verified ingest; post-build audit: GDELT is HTTP-ONLY (broken TLS cert — verify, don’t assume https);
gdelt_file_tsfrom filename;prepareskips non-https junk URLs; warn on emptypriority_terms - dionysus-phase2-findings — the “who is the article about” entity pipeline is MISSING:
gkg.rsparses persons/orgs butmatches_priority(ingest.rs:171) uses them only as a boolean then discards;PreparedArticle(ingest.rs:26) has no entity fields;articles(0001) has no entity columns; NOarticle_mentionstable anywhere (grep=0) despite spec §6; drafted Phase 2 plan writes Qdrantentity_ids: []+ indexes the empty field → entity-filtered retrieval (Elon-tweet use case) non-functional
Embeddings & Enrichment Provider
- dionysus-phase2-findings — CONSTRAINT: Anthropic has NO embeddings API (Messages API is generation-only) — the article-vectorization step CANNOT use a Claude OAuth token; embeddings must come from OpenAI
text-embedding-3-small(dim≤1024) or Voyagevoyage-3-lite(Anthropic’s recommended partner). A Claude token can only serve a GENERATION step (e.g. entity salience). Provider choice not yet locked;Embeddertrait is swappable - dionysus-architecture-decisions — embeddings via swappable API trait (no Python in the engine); cost ~cheap (the VM is the recurring cost, not embeddings)
Implementation & Build
- dionysus-phase1-ingest-skeleton — Phase 1 (Ingest Skeleton) build report: what shipped, 37 tests, live smoke, + the durable reusable learnings the review caught; post-build security/correctness/DRY audit (final commit
21332bd): real bugs found + fixed; meta-lesson — re-validate audit suggestions against reality (curl caught the bad https change) - dionysus — current status (Phase 1 complete + post-build-audited) + the Phase 2+ backlog
- dionysus-phase1-ingest-skeleton — DRY: shared dev-only
dionysus-testsupportcrate; a Cargo dev-dependency cycle is FINE (dev crate not linked into the release binary) - dionysus-phase2-findings — adversarial re-review of the drafted Phase 2 plan:
cost_cap_usd_centsplumbed but never enforced (dead config); fake semaphore concurrency (per-row body runs inline/sequential, never spawned);enrich_poolbuilt with default size not the spec’d max-5; no total.timeout()on the embed HTTP client (onlyconnect_timeout);subject_tokenduplicated betweenenrich.rsandingest.rs(DRY)
Deployment & Infra
- dionysus — v1 managed-first (Qdrant Cloud + Supabase + NATS on existing e2-small) vs Phase-2 self-host
- dionysus-architecture-decisions — phase-gated infra (decisions 4 & 5), the phase-gated @deploy contract,
kind: job15-min limit, Empire zero-backup/DR
Networking & Security
- dionysus-architecture-decisions — decision 8: host
tailscaled(not the unaudited embedded crate), honest egress (serving vs ingest plane) - dionysus-phase1-ingest-skeleton — post-build security audit: GDELT plaintext-ingest hardening —
validate_gkg_urlhost-allowlist +redirect::Policy::limited(0)(MitM/SSRF); 512 MiB decompression-bomb cap (unzip_single); NATS subject-injection slug; residual plaintext-MitM accepted as GDELT’s infra limitation
Observability
- dionysus-architecture-decisions — SigNoz via OTel (reuses empire pipeline), span-per-stage, trace context through NATS, fetch-hit-rate SLI
- dionysus-phase1-ingest-skeleton — OTel 0.32 dual-provider gotcha (wire BOTH tracer + meter or metrics silently no-op); SIGTERM-flush follow-up; post-build audit: record
detect_latencyon error cycles too (outcome=error|ok) so outages aren’t invisible; pollinterval→MissedTickBehavior::Skip(no poll-storm)
Storage & Transport
- dionysus-architecture-decisions — bitemporal Postgres + Qdrant storage split, NATS JetStream bus, partition
article_entities - dionysus-phase1-ingest-skeleton — schema
0001_fastpath.sql(articles/outbox/ingest_checkpoints); testcontainers/Supabase Postgres-version gotchas (PG16 parity, pgcrypto-denied, sqlx Migrator self-locks)