Skip to documentation

Capability clusters

C9 · Platform ops & delivery

The operational backbone of the eli workspace: scheduled cron jobs, the SSE live-update channel, dev/test escape hatches, ops CLIs, install self-heal, MCP binary packaging, and the test pyramid with its CI gates — everything that keeps the platform running, fresh, and honest.

C9 is eli's operational backbone: the scheduled maintenance jobs (daily AI digest, 30-day trash purge) driven by Vercel Cron, the in-process event bus + SSE channel that pushes vault change events to every open browser tab, the test-only dev endpoints that let Playwright manipulate server state, deterministic seeding, benchmark, and ops CLIs (embedding backfill, KMS key rotation), the native-module (better-sqlite3) ABI self-heal that runs on every install, the esbuild packaging of the standalone eli-mcp stdio binary, and the full test pyramid (colocated unit, PGlite harness, adapter contract, MCP harness, pgTAP RLS, Playwright e2e) plus the two GitHub Actions CI gates (perf, RLS). The chokidar watcher and events bus are shared with C1 — C1 owns the indexing side; this page covers the delivery side: the SSE endpoint, its subscribers, heartbeats, and kill switches.

  • Modes: cron routes serve both (local single-vault / saas workspace fan-out); SSE + watcher + dev endpoints + CLIs are local-only; the pgTAP gate validates the saas Postgres layer.
  • Key dirs: app/api/cron/, app/api/events/, app/api/dev/, lib/watch/, scripts/, tests/, .github/workflows/, vercel.json, instrumentation.ts.
  • Depends on: C1 storage adapters + SQLite index, C4 runDigest, C7 service-role Supabase client.
  • Feeds: C2 vault UI (live refresh of every /v page), C5 (packaged MCP binary), every cluster (test + CI coverage).

Capabilities

CapabilityWhat it doesEntry pointsModes
Daily digest cronGenerates a daily digest note per vault (local) or per workspace (saas, service-role fan-out). Bearer CRON_SECRET auth; refuses when the secret is unset. ?date=YYYY-MM-DDoverrides the default "yesterday" UTC window; reruns are idempotent (same digest path upserted). Delegates to runDigest()— same code path as the manual "Generate digest now" button.GET/POST /api/cron/digest, vercel.json cron 0 13 * * *both (Vercel Cron only fires on the Vercel/SaaS deployment)
Trash auto-prune cronHard-deletes soft-deleted notes older than 30 days (?days=N override, min 1). Same bearer auth. Uses updatedAt as trashed-at proxy; caps at 5,000 trashed notes per workspace per run; purges via storage.deleteNote(id, {trash:false}), skipping individual failures.GET/POST /api/cron/trash-prune, vercel.json cron 0 4 * * *both
SSE live-update channelGET /api/events streams vault ChangeEvents (note:created/updated/deleted + path + at) as text/event-stream. 25 s comment heartbeats; X-Accel-Buffering: no; deliberately no backlog replay on connect. Browser reacts with a 500 ms-debounced router.refresh().EventSource('/api/events'), components/vault-events-bridge.tsx (mounted in app/(local)/v/layout.tsx:54), hooks/use-vault-events.ts (public hook, currently unmounted)local
Live-events kill switchesServer env ELI_DISABLE_LIVE_EVENTS=1 skips mounting VaultEventsBridge; client-side window.__ELI_DISABLE_EVENTS__=true disables it per tab.env var (set by playwright.config.ts:45), window flag (components/vault-events-bridge.tsx:23)local
Dev/test endpoint: rescanDrops LocalAdapter caches, re-runs scanVault on the active vault, revalidatePath('/v','layout'). Double-guarded: 403 unless NODE_ENV !== 'production' AND ELI_HOME contains .eli-test.POST /api/dev/rescanlocal (test env only)
Dev/test endpoint: resetCloses every cached better-sqlite3 connection (closeAll), resets LocalAdapter + config caches. Exists because Playwright reuses a dev server whose fds point at a deleted DB inode after global-setup reseeds. Same double guard.POST /api/dev/resetlocal (test env only)
Dev/test endpoint: seed-noteZod-validated {path, body, frontmatter?} creates (or hard-delete-then-recreates) a note via getStorage(), revalidates /v, returns {id, path, versionId}. Gives each mutating e2e test a fresh unique note. Same double guard.POST /api/dev/seed-notelocal (test env only)
Vault seeder CLIGenerates N markdown notes with frontmatter, 3–8 paragraphs, wikilinks, inline tags, across 7 folders. Deterministic mulberry32 PRNG (default seed 42) → byte-identical reruns, so CI can content-address the fixture. Batches of 200 writes; ~10k notes in ~5 s.pnpm seed-vault <dir> <count> [seed] (scripts/seed-vault.mjs)local
Config seeder CLIWrites a ready-made ~/.eli/config.json (mode 0600, dir 0700) with one registered active vault, random 32-byte base64url localToken + mcpToken, openclawCompat: true, git auto-commit on with 30 s debounce. For CI/smoke boots. Not in package.json scripts.node scripts/seed-config.mjs <vault-path> [name]local
Search benchmark CLIBoots LocalAdapter on a seeded vault, runs 100 queries, reports p50/p90/p95/max; exits code 3 when p95 exceeds ELI_PERF_P95_BUDGET_MS (default 200), code 2 on usage error.pnpm bench-search <vault-dir> (scripts/bench-search.mjs, via tsx)local
Embedding backfill CLIBatch-embeds every note in a vault/workspace outside HTTP — skips the AI rate-limit bucket and needs no user session; key resolution mirrors lib/ai/resolver.ts (AI_GATEWAY_API_KEY env or config aiKey), exits with a hint when neither is set. Idempotent via listNotesMissingEmbedding; --batch N (default 32), --dry-run.pnpm embed:backfill --vault <path> or --workspace <uuid> (scripts/embed-backfill.mjs, via tsx)both
AI-key KMS rotation CLIRe-encrypts every ai_keys.ciphertext row from ELI_KMS_KEY_OLD to ELI_KMS_KEY (compromise response / quarterly rotation). One transaction per row, decrypt-verifies new ciphertext before commit, refuses keys shorter than 16 bytes; needs SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY; exits 2 on usage error.pnpm rotate-ai-keys (scripts/rotate-ai-keys.mjs)saas
Native ABI self-healPostinstall probe of better-sqlite3 by actually opening :memory: and running SELECT 1 (bare require() would mask ABI mismatch); on NODE_MODULE_VERSION/ERR_DLOPEN_FAILED/invalid-ELF signatures, detects the package manager from the lockfile and runs the right rebuild. SKIP_POSTINSTALL=1 opts out. Never fails the install.pnpm postinstall (automatic), pnpm rebuild-nativelocal
MCP stdio binary packagingesbuild-bundles lib/mcp/stdio.tsdist/lib/mcp/stdio.js (ESM, node22, path aliases, createRequire banner; server-only/client-only aliased to the test stub). Natives + SDKs stay external. Runs in prepack; published bin is bin/eli-mcp.mjs.pnpm build:mcp, prepack hook, npx eli-mcplocal
Test commandspnpm test / test:watch (vitest), mcp:test (tests/mcp only), test:e2e / test:e2e:ui (Playwright), plus lint, lint:fix, typecheck, format, format:check. Dev server on :3737, e2e server on :3838.package.json:23-32local
CI: perf gateOn push/PR touching local-storage/SQLite paths (plus workflow_dispatch): Node 22 + pnpm 10, seeds a 10k-note vault (cached by hash of the deterministic seed script), runs bench-search with ELI_PERF_P95_BUDGET_MS=450; exit 3 fails the job..github/workflows/perf.ymllocal
CI: RLS conformance gateOn push/PR touching pg migrations or tests/rls: boots pgvector/pgvector:pg17 container, installs pgTAP + pg_prove, applies every lib/db/migrations/pg/*.sql, runs pg_prove tests/rls/*.sql..github/workflows/pgtap.ymlsaas (validates the Postgres/Supabase RLS layer)
Boot-time file watcherinstrumentation.ts register() — Next calls once at server boot. Guards: NEXT_RUNTIME === 'nodejs' and ELI_MODE unset-or-local. Starts the chokidar watcher for the active vault so external edits update the SQLite index without manual rescan; failures non-fatal (lazy start on first storage-touching request).Next.js instrumentation register()local

System view — simplified

System view — simplified

This cluster is everything that keeps eli running, fresh, and honest: scheduled jobs that the app itself never has to remember to run, a push channel that makes multiple tabs (and external editors) converge on the same view, and the tooling/test/CI layer that keeps the platform installable and correct. Standalone, it is fully usable against just a checkout: pnpm install self-heals the native SQLite binding, seed-vault + bench-search benchmark search on a synthetic 10k-note vault, the entire test pyramid runs without any external service (PGlite gives it an in-process Postgres), and both cron endpoints can be curl'd with a bearer secret against a local next dev server. The only piece that needs external infrastructure is the automatic schedulingof crons (Vercel) and the pgTAP gate's Postgres container (CI-provisioned).

System view — detailed

System view — detailed
ComponentRoleFiles
Cron digest routeDaily digest generator; bearer-secret-authed; fans out per-vault (local) or per-workspace via Supabase service role (saas); delegates to runDigestapp/api/cron/digest/route.ts
Cron trash-prune routeAuto-purge of soft-deleted notes older than N days (default 30); same auth + fan-out pattern; hard-deletes via deleteNote({trash:false})app/api/cron/trash-prune/route.ts
Cron schedule / deployment manifestVercel Cron config — digest 13:00 UTC, trash-prune 04:00 UTC. Only deployment-topology file in the repo: SaaS = Next.js on Vercel + Supabase; Local = self-hosted next dev/start -p 3737 with no automatic cron invokervercel.json
SSE events endpointStreams ChangeEvents as text/event-stream; 25 s heartbeat; no backlog replay; unsubscribes + closes on request abort; force-dynamic nodejs runtimeapp/api/events/route.ts
In-process events busProcess-global singleton (globalThis.__ELI_EVENT_BUS__) with listener Set + 256-entry recent ring buffer; emit() swallows per-listener errors; recentEvents() exists but the SSE route intentionally ignores itlib/watch/events-bus.ts
Chokidar watcher (bus publisher #1)Watches vault dir for .md add/change/unlink with ignoreInitial + awaitWriteFinish (60 ms stability, 30 ms poll), ignoring .git/node_modules/.next path segments at any depth; suppresses adapter-write echoes via markEcho() (750 ms TTL); updates incremental SQLite index then emits; process-global registrylib/watch/chokidar.ts
Adapter-write emits (bus publisher #2)note:created/deleted emitted directly from LocalAdapter write paths (lines 234, 316, 365, 372, 406) so in-app writes propagate without the fs round-triplib/storage/local/writes.ts
SSE client subscribersVaultEventsBridge mounted once in the vault layout: EventSource('/api/events') → 500 ms-debounced router.refresh(); useVaultEvents is an undebounced public variant (optional onEventcallback, refreshes per event relying on Next's internal coalescing), currently unmountedcomponents/vault-events-bridge.tsx, hooks/use-vault-events.ts, app/(local)/v/layout.tsx
Boot instrumentationregister() starts the watcher at server boot on the Node runtime in local mode; failures non-fatalinstrumentation.ts
Dev/test endpointsThree POST-only escape hatches for Playwright, each 403 unless non-prod AND ELI_HOME contains .eli-testapp/api/dev/rescan/route.ts, app/api/dev/reset/route.ts, app/api/dev/seed-note/route.ts
Seeding toolingDeterministic N-note fixture generator; ready-made ~/.eli/config.json writer for CI/smokescripts/seed-vault.mjs, scripts/seed-config.mjs
Ops CLIsembed:backfill batch-embeds outside HTTP (no rate bucket, no session, idempotent; arg parsing split into embed-backfill-args.mjs for the tests/unit suite); rotate-ai-keys re-encrypts ai_keys.ciphertext old→new KMS key, one verified transaction per rowscripts/embed-backfill.mjs, scripts/embed-backfill-args.mjs, scripts/rotate-ai-keys.mjs
Native module handlingProbe-based better-sqlite3 ABI check, lockfile-based PM detection, auto-rebuild, SKIP_POSTINSTALL=1 opt-out; never fails installscripts/ensure-native.mjs
MCP bin builderesbuild bundle of lib/mcp/stdio.ts dist/lib/mcp/stdio.js; natives/SDKs external; server-only/client-only stubbed; runs in prepackscripts/build-mcp-bin.mjs, bin/eli-mcp.mjs
Vitest configNode env; colocated lib/**+app/** .test.ts plus tests/unit, tests/_helpers, tests/adapter, tests/mcp; excludes tests/e2e; coverage scoped to lib/; aliases server-only/client-only → empty stubvitest.config.ts, tests/_helpers/server-only-stub.ts
Playwright config + fixturesPort 3838, chromium-only, workers=1, serial, retries 2 in CI, trace/video retain-on-failure; webServer = next dev --turbopack with .eli-test fixture home/vault, ELI_DISABLE_LIVE_EVENTS=1, ELI_LEGACY_EDITOR=1; global setup reseeds 3-note fixture (git.auto=false) + best-effort /api/dev/resetplaywright.config.ts, tests/e2e/global.setup.ts, tests/e2e/_setup.ts, tests/e2e/_paths.ts
Colocated unit suite~75 .test.ts files under lib/ and app/ — storage helpers, MCP tools/auth/rate-limit/stdio, AI digest/chunking/pricing, git, config, clipper, templates, server actions, route handlerslib/**/*.test.ts, app/**/*.test.ts
tests/unitOne suite: parseEmbedBackfillArgs CLI arg parsing for the embed:backfill scripttests/unit/scripts/embed-backfill-args.test.mjs
PGlite harnessIn-process Postgres with pgvector + auth.uid() stub; runs all 16 pg migrations; ~20 tests: migration idempotency, notes_search ranking, notes_save 40001 conflict, wikilink rewrite, bootstrap trigger, RLS-enabled on 11 tables, policy-name inventorytests/_helpers/pglite.ts, tests/_helpers/pglite.test.ts
Adapter contract suiteShared StorageAdapter conformance (ADR-0004) with per-adapter caps flags; runs against Local (favorites skipped), Memory, JsonFiletests/adapter/contract.ts, tests/adapter/{local,memory,json-file}.spec.ts
MCP harnessSame registerTools surface over stdio (InMemoryTransport linked pair) and HTTP (createMcpHandler + fake Request); locks the exact 16-tool list and a create→edit→search→diff→restore lifecycletests/mcp/harness.ts, tests/mcp/tools.spec.ts
pgTAP RLS suite_setup.sql stubs Supabase env (auth.uid(), roles, act_as helpers); 21 assertions across notes select/write and share-link scopingtests/rls/_setup.sql, tests/rls/notes_select.sql, tests/rls/notes_write.sql, tests/rls/share_links.sql
Playwright e2e (7 specs)Redirects/lenses, note view + autosave/revert, command palette, daily note + theme, new-note dialog + breadcrumbs, vault picker, zero-console-error nettests/e2e/01…07-*.spec.ts
CI workflowsperf.yml 10k-note search-latency gate; pgtap.yml RLS conformance vs pgvector:pg17 container. No lint/typecheck/vitest workflow exists.github/workflows/perf.yml, .github/workflows/pgtap.yml
ESLint configFlat config: next + core-web-vitals + typescript-eslint with relaxations; ignores build/test artifacts and scripts/eslint.config.mjs

Behavior contracts locked by tests. The colocated suites are not just unit coverage — several pin exact behavioral contracts: app/api/_e2e.test.ts locks status-code/payload contracts for /v1/openapi.json, /v1/models, /api/import (existing path → updated, new → created), /api/search/hybrid (kind whitelist fts/semantic/hybrid, else 400), and both cron routes (401 on absent/mismatched bearer, digest 200 skipped:['no-active-vault'], prune default 30 days) with storage mocked; app/api/ai/_routes.test.ts locks all five /api/ai/* endpoints' 400 / 503-no-AI-key / 429 contracts, including the shared 60-per-minute 'local' rate bucket from lib/mcp/ratelimit that MCP and the AI routes both consume, and graceful degradation (extract-tasks returns 200 created:[] on non-JSON model output); lib/mcp/tools/p3-tools-04.test.ts pins add_comment version-pinning, daily_note real-calendar-date validation, and apply_template pass-through; server-action suites (app/_actions/{pin,inbox-toast,digest,projects,templates}.test.ts) lock semantic invariants (unpin deletes _pinned rather than setting false, dual-signal leftInbox, frontmatter sibling-field preservation). No suite makes live model calls — an AI-sandbox e2e is noted as future work (app/api/ai/_routes.test.ts:7-12).

Data flow — simplified

Data flow — simplified

The load-bearing runtime flow: any change to a .md file on disk (external editor, agent, git checkout) is picked up by the chokidar watcher, incrementally re-indexed into SQLite, and broadcast over the in-process bus to every connected SSE client. Each browser tab collapses bursts with a 500 ms debounce and calls router.refresh(), so React Server Components re-render against the freshly updated index. In-app saves take a shortcut: lib/storage/local/writes.ts emits directly onto the bus and calls markEcho() so the watcher ignores the resulting filesystem echo.

Data flow — detailed

(a) Vault change → bus → SSE → debounced refresh across tabs (local mode)

Data flow — detailed (a): vault change → bus → SSE → debounced refresh across tabs

(b) Cron digest run across modes

Data flow — detailed (b): cron digest run across modes

The trash-prune cron (app/api/cron/trash-prune/route.ts) follows the identical shape: same badAuth bearer check, same local/saas fan-out, but per adapter it lists up to 5,000 onlyTrashed notes, skips any with updatedAt newer than the cutoff (?days or 30), and hard-purges the rest one by one, swallowing individual failures.

Works separately / works together

Standalone

With every other cluster switched off, C9 still delivers: a self-healing install (ensure-native.mjs makes pnpm install survive Node ABI bumps with zero user action), deterministic fixture generation (seed-vault.mjs produces byte-identical 10k-note vaults), a search benchmark with a hard exit-code budget, a config bootstrapper for headless CI boots (seed-config.mjs), and a complete test pyramid that runs with no external services — PGlite provides in-process Postgres, the MCP harness uses in-memory transports, and Playwright brings its own fixture vault under .eli-test/. The cron endpoints work against any running instance via curl -H "Authorization: Bearer $CRON_SECRET"; only automaticscheduling needs Vercel. The SSE channel standalone is a generic "this vault changed" push feed any client could consume via EventSource('/api/events').

Composed

  • C4 AI platform — the digest cron delegates to runDigest() in lib/ai/digest-runner.ts, the exact code path behind the UI's manual "Generate digest now" action (app/api/cron/digest/route.ts:33-35 docstring); digest logic itself lives in C4, C9 only schedules and auths it. The two callers are distinguishable by route tag: manual runs pass app/_actions/digest.generateNow and in SaaS are session-scoped to the single eli_ws-cookie workspace via the user's RLS client — cross-workspace service-role fan-out is reserved for the cron.
  • C1 core data & storage — both cron routes consume the storage abstraction (LocalAdapter.forVault / SupabaseAdapter.fromClient); the events bus is fedby C1's chokidar watcher (which also drives lib/index/incremental.updatePath) and by lib/storage/local/writes.ts emit calls; the dev endpoints reach into C1 internals (lib/db/client.sqlite.closeAll, LocalAdapter._resetCache, lib/index/scanner.scanVault, lib/config._resetCacheForTests).
  • C2 authoring UX VaultEventsBridge is mounted in app/(local)/v/layout.tsx:54, so every RSC page under /vis indirectly refreshed by change events; C2's note list, backlinks, and lenses stay live because of this cluster.
  • C7 SaaS collaboration — cron fan-out uses lib/auth/supabase.createSupabaseServiceRoleClient (RLS-bypassing, tracked as SERVICE-ROLEcomments); the pgTAP gate is the CI enforcement of C7's RLS policies.
  • C5 agent surface build-mcp-bin.mjs packages C5's lib/mcp/stdio.ts into the published eli-mcp bin; tests/mcplocks C5's 16-tool surface over both transports.
  • C3 semantic search tests/unit/scripts/embed-backfill-args.test.mjscovers the embed-backfill CLI's arg parsing; perf.ymlgates C1/C3's search latency.
  • e2e ↔ dev endpoints — Playwright global setup POSTs /api/dev/reset, spec 02 mints per-test notes via /api/dev/seed-note, spec 06 busts the config cache via /api/dev/rescan after directly editing .eli-test/home/config.json.

Load-bearing details

  • Cron auth is strict equality against `Bearer ${env.CRON_SECRET}`; an unset CRON_SECRET makes badAuth() return true → permanent 401, never wide-open (app/api/cron/digest/route.ts:46-51, app/api/cron/trash-prune/route.ts:32-36). The x-vercel-cron header is explicitly documented as untrusted (digest route comment, lines 15-18). CRON_SECRET is zod-optional (env.ts:98).
  • Both cron routes alias GET→POST because Vercel Cron sends GET (digest/route.ts:57-61, trash-prune/route.ts:113-115); both export dynamic = 'force-dynamic'.
  • The digest window is exactly 00:00:00Z→24:00:00Z of the target day, so multiple runs the same day are idempotent — they upsert the same digest path (app/api/cron/digest/route.ts:20-24 docstring, 53-55, 68-76).
  • Trash prune has no trashedAt column — it proxies via updatedAt("the soft-delete write was the last update on a trashed row, by construction") and caps at 5,000 trashed notes per workspace per run (app/api/cron/trash-prune/route.ts:19-25,43-44).
  • The SSE route deliberately does not replay the 256-entry backlog on connect — replay caused router.refresh() flurries that masked navigations and made e2e flaky (app/api/events/route.ts:31-37); recentEvents() (lib/watch/events-bus.ts:43-45) is therefore dead to the SSE path.
  • Bus and watcher registry survive Next dev HMR via globalThis singletons: __ELI_EVENT_BUS__ (lib/watch/events-bus.ts:13-22) and __ELI_WATCHERS__ (lib/watch/chokidar.ts:27-34). The flip side: fan-out is single-process only and cannot span serverless instances — the SaaS answer is Supabase Realtime postgres-changes on notes (components/realtime/note-watcher.tsx), which shows a refresh-invite toast (never auto-replaces the buffer) and filters self-edits via a window-pinned set of version ids.
  • GET /api/events performs no auth check of its own — any client that can reach the local server can subscribe to the change feed (app/api/events/route.ts:20).
  • Echo suppression: adapter writes call markEcho(vault, relPath)with a 750 ms TTL so chokidar doesn't double-index files the adapter itself just wrote (lib/watch/chokidar.ts:36-58).
  • All three /api/dev/* endpoints share a double guard: 403 when NODE_ENV === 'production' or when ELI_HOME doesn't contain the substring .eli-test— they can't fire on a real install even in dev mode (rescan/route.ts:17-23, reset/route.ts:19-24, seed-note/route.ts:21-26).
  • /api/dev/reset exists specifically because playwright.config.ts reuseExistingServer keeps better-sqlite3 fds open on a deleted DB inode after global-setup reseeds; closeAll() + cache resets force reopening the new file (app/api/dev/reset/route.ts:7-17).
  • seed-vault.mjs is byte-deterministic via mulberry32 (seed 42), which perf.yml exploits to cache the 10k-note fixture keyed on hashFiles('scripts/seed-vault.mjs') (.github/workflows/perf.yml:73-84).
  • bench-search.mjs exits code 3 when p95 > ELI_PERF_P95_BUDGET_MS(default 200; CI sets 450 for shared runners) — that exit code is the perf gate's entire failure mechanism (scripts/bench-search.mjs:89-92).
  • ensure-native.mjs probes better-sqlite3 by instantiating a :memory: DB and running SELECT 1, because many native packages only dlopen on first use, not on require (scripts/ensure-native.mjs:42-52); ABI-mismatch signatures matched by regex /NODE_MODULE_VERSION|ERR_DLOPEN_FAILED|invalid ELF header|not a valid Win32 application|Could not locate the bindings file/i (line 86); it never fails the install.
  • build-mcp-bin.mjs reuses tests/_helpers/server-only-stub.ts as the esbuild alias for both server-only and client-only in the shipped MCP binary — a test helper is load-bearing in the production bin build (scripts/build-mcp-bin.mjs:83-86).
  • e2e runs with ELI_LEGACY_EDITOR=1 (forces the legacy <textarea data-testid="note-editor">; BlockNote's contenteditable breaks End-key semantics) and ELI_DISABLE_LIVE_EVENTS=1 (SSE refresh races router.push) — so e2e covers neither BlockNote editing nor the live SSE bridge (playwright.config.ts:38-54).
  • e2e is single-worker, serial, chromium-only, on port 3838 against next dev --turbopack — not a production build (playwright.config.ts:17-34).
  • instrumentation.ts only starts the watcher when NEXT_RUNTIME === 'nodejs' and ELI_MODE is unset or 'local'; SaaS deployments never run chokidar (instrumentation.ts:16-17).
  • tests/adapter/local.spec.ts skips the favorites capability because LocalAdapter favorites persist in ~/.eli/config.json keyed by registered vault id, and the contract factory creates an unregistered tmp vault (tests/adapter/local.spec.ts:50-54).
  • The MCP tool surface is locked by test to exactly 16 tools (tests/mcp/tools.spec.ts:44-67); the HTTP path calls createMcpHandler with a fake Request — no real server; auth/rate-limit failure modes live separately in lib/mcp/auth.test.ts.
  • vercel.json contains onlythe two cron entries — the sole Vercel-specific deployment config in the repo. SaaS topology is "Next.js on Vercel + Supabase"; local topology is self-hosted next dev/start -p 3737 (package.json:15,22) where crons must be invoked manually.
  • package.json pins engines.node >= 22.11.0, and pnpm.onlyBuiltDependenciesallowlists build scripts for exactly better-sqlite3, esbuild, and sharp — pnpm blocks every other dependency's postinstall, so ensure-native.mjs only ever has one native module to heal.

Gaps and partially wired

  • No CI for the bulk of the pyramid. Only two workflows exist (perf.yml, pgtap.yml); nothing in .github/workflows/ runs lint, typecheck, the ~75-file vitest suite, or the e2e suite — those gates are local-only conventions.
  • Stale SSE docstring. app/api/events/route.ts:17-18still claims "On open, recent backlog is replayed" while the code comment at lines 31-37 (and the code) deliberately does the opposite. The doc lies; the code is right.
  • recentEvents() is dead code on the delivery path (lib/watch/events-bus.ts:43-45) — kept on the bus but intentionally unused by the SSE route.
  • hooks/use-vault-events.ts is a public hook with zero mounts VaultEventsBridge inlines its own EventSource to own the 500 ms debounce; the hook itself is undebounced (per-event router.refresh() plus an optional onEvent callback) and exists for future consumers only.
  • Missing Supabase adapter-contract run. tests/_helpers/pglite.ts:17-19 references tests/adapter/supabase.spec.ts, but no such file exists — the shared conformance suite runs only against Local/Memory/JsonFile, so the SaaS adapter is untested at the contract level.
  • CRON_SECRET is optional in the env schema (env.ts:98): a deployment that forgets to set it gets both cron endpoints permanently returning 401 — safe, but silently no-op (digests and trash purge just stop happening).
  • No cron invoker in local mode. vercel.json schedules only apply on Vercel; a self-hosted local install must curl the cron endpoints itself (or never get digests/pruning).
  • e2e blind spots by design: BlockNote editing (ELI_LEGACY_EDITOR=1) and the live SSE bridge (ELI_DISABLE_LIVE_EVENTS=1) are excluded from Playwright coverage; the suite also runs against next dev --turbopack, not a production build.
  • Trash prune approximations: no trashedAtcolumn (updatedAt proxy can extend a note's trash life if it is touched post-trash), and the 5,000-per-workspace cap means a larger backlog only drains across multiple daily runs.
  • seed-config.mjs is unwired from package.json scripts — invocable only as node scripts/seed-config.mjs.
  • tests/unit is nearly empty — a single CLI-arg-parsing suite (tests/unit/scripts/embed-backfill-args.test.mjs); everything else is colocated.

See also

C1 core data & storage (indexing side of the watcher/bus), C4 AI platform (digest logic), C7 SaaS collaboration (RLS policies the pgTAP gate enforces), C10 end-to-end journeys, and the platform overview.