From f35c2a85a541cd6fabb22ecf1bcb6667d309fde3 Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 5 Jun 2026 23:43:17 +0200 Subject: [PATCH] docs: scheduled-discovery env + single-replica constraint; VISION gate-clock reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit homelab-integration.md gains a "Scheduled discovery" section documenting TAPIR_DISCOVERY_INTERVAL and TAPIR_FETCH_RATE and the load-bearing single-replica constraint (in-process scheduler → replicas: 1 is required; >1 double-runs discovery). VISION Stage 0 carries a pointer to ADR-018's gate-clock reset so nothing in docs implies the window started before unprompted use was possible. Co-Authored-By: Claude Opus 4.8 (1M context) --- VISION.md | 5 +++++ docs/homelab-integration.md | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/VISION.md b/VISION.md index 0ca53f9..3fd330d 100644 --- a/VISION.md +++ b/VISION.md @@ -90,6 +90,11 @@ to the next stage's ambition until the current stage's test passes. table (see infra/Tapir build) answers "returned/read in ≥2 distinct weeks" even without an action click — the honest signal for a *reading* product. Login events accrue only from their deploy date onward, so the gate window's data begins then. +- **Gate-clock reset (ADR-018).** The 3–4 week window starts when in-process scheduled discovery + + auto-summarize ship — before that, unprompted use was impossible, so the prior window + measured nothing (this is starting the clock when the experiment can actually run, not a reset + to dodge a failing gate). The 2026-07-01 check-in referenced above moves accordingly to ~3–4 + weeks after this deploys. See DECISIONS.md ADR-018. - **This is the gate.** Hardening (Stage 1) and any SaaS ambition stay deferred until this behavioural signal exists. Note: multi-user machinery was deliberately built *ahead* of this gate (ADR-012) with isolation enforced — that was an explicit, recorded call, not a diff --git a/docs/homelab-integration.md b/docs/homelab-integration.md index 23d9c3d..defddd4 100644 --- a/docs/homelab-integration.md +++ b/docs/homelab-integration.md @@ -191,3 +191,23 @@ snapshot time — check brain or the live cluster before depending on them._ - `user_identities(dex_subject → user_id)` table is **intentionally NOT RLS-enabled** (it's auth plumbing, holds no user data; data isolation is on the user-owned tables). All data access after subject resolution goes through `withUser`. + +## Scheduled discovery (ADR-018, verified 2026-06-05) + +`tapir serve` runs discovery for **all users** in-process on a timer (no CronJob). Two env +knobs plus one load-bearing deployment constraint: + +- `TAPIR_DISCOVERY_INTERVAL` — Go duration, e.g. `2h`. The cadence the serve process runs a + discovery pass for every registered user (run-once-on-startup, then every interval). + **Unset or `0` = disabled** (dev/tests never auto-fetch). +- `TAPIR_FETCH_RATE` — Go duration, default `2s`. The **process-wide per-egress-IP caption-fetch + rate gate** (ADR-014 item 2). Every caption fetch — scheduler runners *and* the web "Summarize" + click-path — serialises through this one limiter so the pod cannot collectively trip 429s. `0` + = unlimited (dev/tests). This is the precondition that makes auto-summarize-on-a-schedule safe; + do not raise it aggressively without watching for 429s. +- **SINGLE-REPLICA WARNING (load-bearing).** The scheduler lives in the web process, so + `replicas: 1` in the deployment manifest is load-bearing: running `tapir serve` at >1 replica + makes **every** replica run the discovery loop → every user fetched in parallel from the same + egress IP (429s + duplicate work). Do **not** scale `serve` past 1 replica without first moving + discovery to a k8s CronJob or adding leader election. The process logs a `Warn` at startup when + scheduled discovery is enabled, as a reminder.