Appearance
Intelligence Rollout — Flags, Defaults & Reversibility
How NanaSelect ships its three AI-model swaps under a feature-flagged, reversible rollout where the deterministic path is the standing fallback — not dead code (issue #1193, part of capability #1185). Each swap is independently flag-toggled; on a flag being off, a model error, a timeout, or budget exhaustion, the pipeline degrades to the deterministic path with no buyer-facing hang and no blocked enrichment. It enforces the quality thresholds (#1192), spends under budget governance (#1191), and respects the egress posture (#1190).
The one-line version: every swap ships OFF; it flips on only after it clears its #1192 go/no-go bar with Paul's approval; and flipping it off — or any request-time model failure — instantly and completely restores the deterministic behavior.
Flag inventory (AC-01)
The single source of truth is INTELLIGENCE_FLAGS in src/lib/server/intelligence-flags.ts; resolveIntelligenceFlagStates(env, egressEnabled) reports each flag's live state from the same resolvers the swaps use, so the inventory can never drift from what actually gates the code.
Where to look it up today: this inventory is code + this doc — no
/adminscreen renders it yet (#1581 tracks surfacing it in/admin/ai). To check live state, read the flag sources:wrangler.jsoncvarsfor the env-backed flags, and/admin/privacyfor themedia.egress_enabledtoggle.
| Swap | Flag | Backing | Flip | Default | Degrade path |
|---|---|---|---|---|---|
| corpus-retrieval (#1187) | CORPUS_HYBRID_RETRIEVAL | env var | redeploy | OFF | lexical scoring (pre-#1187 retrieval) |
| visual-tags (#1188) | media.egress_enabled | app_settings | instant (admin toggle) | OFF | deterministic stub analyzer (#1123), no egress |
| media-similarity (#1189) | MEDIA_SIM_VECTORIZE | env var | redeploy | OFF | brute-force D1 cosine (pre-#1189) |
- Independent — each swap has its own flag; turning one on/off never touches another.
- Declared config — env flags live in
wrangler.jsoncvars(alsoMEDIA_SIM_TOPK,CORPUS_HYBRID_W_*); the visual-tags flag is anapp_settingsrow flipped from /admin/privacy (instant, no deploy — "flippable without a deploy where feasible", AC-01).
Defaults & the go/no-go gate (AC-02)
Every flag defaults OFF (defaultOn: false) — the conservative rollout of decision #1195. A flag is flipped on only after its swap clears its documented #1192 bar (DEFAULT_EVAL_BARS, linked from each inventory entry) and Paul authorizes it. Below the bar, or with the flag off, the deterministic path serves prod. The harness reports GO/NO-GO; a human holds the flip.
The degrade guarantee (AC-03)
The deterministic path is the standing fallback at request time, not just when a flag is off. Each swap degrades on any model failure and never hangs:
| Swap | Degrade trigger | Falls back to | Seam |
|---|---|---|---|
| corpus-retrieval | flag off · no request context · empty/failed vector arm | lexical scoring | resolveVectorBlend (try/catch → undefined) |
| media-similarity | flag off · absent binding · index error · empty result | brute-force cosine | similarAssets (try/catch → rankBySimilarity) |
| visual-tags | flag off · no real analyzer wired | stub analyzer | selectMediaAnalyzer (fail-closed) |
| all model calls | rate-limit / transient error / budget exhaustion | bounded retry → abort to partial | withModelRetry (rethrow-on-exhaustion, never loops) |
Because the fallback is the original deterministic behavior, a model outage is invisible to the buyer — grounding still returns lexical matches, "assets like this" still returns brute-force neighbours, and the visual-tag pass still proposes stub tags. This is asserted holistically in src/lib/server/intelligence-rollout.spec.ts.
Reversibility (AC-04)
A flip-off is immediate and complete. The flags gate which path runs, not stored data, so turning a swap off restores its deterministic behavior with no residual state:
- No corruption — the deterministic paths read the same D1/lexical inputs they always did; the model paths only add (Vectorize vectors, tag proposals for review), they never mutate or remove the deterministic inputs. The corpus/media D1 vectors are retained as the degrade seed (not deleted), and visual-tag proposals stay in the review queue, never live, until a human accepts them.
- Instant where it matters — the visual-tags flag (
app_settings) flips from the admin with no deploy; the env flags flip on the next deploy. Either way the next request after the flip uses the deterministic path — there is no warm-up or drain. - Proven —
resolveIntelligenceFlagStateswith everything off reports every swap deterministic; the rollout spec asserts a flip-off returns the fully-deterministic posture.
Operating the rollout
- Land the swap behind its flag (all three are already flag-gated, default OFF).
- Run its #1192 harness (
corpus:eval/tag:eval/sim:eval) → GO/NO-GO. - On GO and Paul's approval, flip the flag: the admin toggle for visual-tags, or set the env var + deploy for corpus-retrieval / media-similarity.
- To reverse at any time, flip it back off — the next request serves deterministic.
See the flag inventory for the authoritative list, and the deploy & activate runbook for the full ordered ops sequence (#1226).