diff --git a/.gitignore b/.gitignore index dc23a0e..8947b2b 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ zig-pkg/ scripts/bench-results.json __pycache__/ .logfire/ +scripts/.backfill-plc-state.json diff --git a/CLAUDE.md b/CLAUDE.md index 030eb98..302b93f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,7 +5,7 @@ README.md has the architecture; this file is the operational contract for assess ## the serving invariant -No request does work proportional to the actor corpus (~6M actors). The request path +No request does work proportional to the actor corpus (~8M actors). The request path reads a small set of precomputed prefix keys, merges the live overlay, hydrates a capped list, and returns JSON. Any change that introduces corpus-proportional work on the request or cron path is a regression — that exact mistake froze /stats once (full-scan `COUNT(*)` diff --git a/README.md b/README.md index d3a2455..0a5eccc 100644 --- a/README.md +++ b/README.md @@ -57,13 +57,15 @@ just test-services # cd services && zig build test --summary all cd services && zig build run ``` -The default Zig run mode is the long-running service binary. Fly config controls -the role: - -- ingest service: Jetstream on, sync/search off as configured in `fly.toml` -- search service: Jetstream off, sync + index promotion + prefix search on in - `fly.search.toml` -- snapshot builder: `MODE=indexer` in `fly.indexer.toml` +The one binary picks its role from the **required `MODE` env var** (no default — +boot fails without it), set per app in fly config: + +- `MODE=ingester` (`fly.toml`): consume Jetstream, batch actor updates to the + worker, run Turso schema migrations. Does NOT keep a local replica. +- `MODE=search` (`fly.search.toml`): sync Turso → local replica, promote/attach + prefix-index snapshots, serve `/search` from snapshot + overlay. +- `MODE=indexer` (`fly.indexer.toml`): offline snapshot build, then exit. Runs as + an ephemeral / `--schedule daily` Fly machine, not a long-running service. The ingest service requires `TYPEAHEAD_URL` and `TYPEAHEAD_SECRET`. R2 and Turso credentials are provided as Fly/Worker secrets in production. diff --git a/services/fly.toml b/services/fly.toml index 81a7bb4..7bc22f5 100644 --- a/services/fly.toml +++ b/services/fly.toml @@ -16,7 +16,6 @@ primary_region = 'ewr' [env] MODE = 'ingester' TYPEAHEAD_URL = 'https://typeahead.waow.tech' - SQLITE_TMPDIR = '/data/tmp' [processes] app = './typeahead-ingester' diff --git a/services/src/db/sync.zig b/services/src/db/sync.zig index 6dd1aba..c938691 100644 --- a/services/src/db/sync.zig +++ b/services/src/db/sync.zig @@ -933,9 +933,8 @@ fn snapshotOldFtsRow(conn: zqlite.Conn, did: []const u8, out: *OldFtsRow) void { } /// Per-row incremental apply: snapshot old FTS values, INSERT OR REPLACE the -/// actor, then FTS5 special-delete the old entry and insert the new one. -/// Mirrors the per-row maintenance pattern in ingest.zig::writeToLocal so the -/// local FTS table stays consistent without periodic full rebuilds. +/// actor, then FTS5 special-delete the old entry and insert the new one. Keeps +/// the local FTS table consistent without periodic full rebuilds. /// `caller` is just for log context ("incremental" vs other future callers). fn applyActorUpdate(conn: zqlite.Conn, row: anytype, caller: []const u8, octx: ?OverlayCtx) !void { const did = row.text(Col.did);