Rot vectors and where to look first
The system is single-operator and accreted across many decisions. Some coupling is deliberate (storage routing), some is the cost of not having a v2 refactor yet. This page documents both — what to watch for, and where to start when something changes.
Adding a new domain — the 6 touch points The 6-touch-point rule is conservative. Some changes cascade beyond these six. A storage backend change for an existing door (e.g. moving learning to a DB) would also require migration schemas, a new reconciler branch, and possibly an RLS policy.
The model implies "just add an entry to _domains.yaml." Reality
is six places, of which only one is declarative:
_domains.yaml is
declarative; the other five are manual edits.
Hardcoded coupling — find before refactoring
Renaming a domain (e.g. finance → markets) requires touching
every place the literal string appears. Inventory of known sites:
| Site | Lock type |
|---|---|
TradingV migration — CHECK (domain = 'finance') on the recommendations table | SQL constraint |
TradingV Pydantic schema — Literal["finance"] | Python type |
Supabase recommendations.domain CHECK (domain IN ('fitness','nutrition')) | SQL constraint |
Lovable WHERE-clause filter — frontend + server filter on domain IN ('fitness','nutrition') | App code |
Phase W reconciler branch — if domain == 'finance' selects backend | Slash command |
/rx-*-status regex — filename pattern check | Slash command |
Operator UUID hardcoded as an env var in the laptop .env | Env var |
kb-mcp sources.yaml port routing | MCP config |
Known limitations to plan around
Substring hypothesis ↔ rec linkage (finance) — now MITIGATED
D-046 originally resolved hypothesis_id by searching the
rec's body markdown for the hypothesis slug. False-positive prone:
a rec mentioning "NVDA" matched every hypothesis whose slug contained
"nvda" — even unrelated ones.
Mitigated. Recs now carry explicit
linked_hypothesis_ids named at compose time
(match_type="explicit"). The substring heuristic is
demoted, not removed: it only runs as a fallback suggestion,
any already-explicitly-linked hypothesis suppresses its substring match,
and remaining hits are tagged match_type="substring_fallback".
The landmine ledger (below) tracks removing the fallback entirely at the
second user.
Embedding model immutability
embedding_dim is baked into the SQLite cache schema. Changing
EMBEDDING_MODEL env without deleting the cache crashes
startup. There is no automatic re-embed sweep.
Procedure: stop indexer → rm cache-<domain>.db →
restart → wait for full re-index (minutes to tens of minutes
depending on corpus size).
Learning empty corpus
Indexer Port 4 is live but the vault has no learning
content. bundle(scope="learning") returns 0 results.
The /rx-learning command tolerates this by setting
thesis_match=0 and continuing.
Mitigation: operator must populate Videos/learning/_ingest_queue.md and run an ingest.
Snooze auto-revive timezone drift
D-039 noted a timezone bug in finance auto-revive — snoozed_until
compared against NOW() at the application layer vs
NOW() at the DB layer in inconsistent ways. The fix lives
inside /rx-finance.md step 0.5 but is not codified as a
regression test. Risk: silent regression on any rewrite of the
command.
Cross-cutting commands learning-aware (resolved by D-048, 2026-05-19)
Historical: when D-047 shipped the learning slice on 2026-05-18,
/rx-board, /rx-digest, and
/rx-analyze were left enumerating
{fitness, finance, nutrition} only — invisible breakage
for any learning rec that landed.
Resolved by D-048 (Phase Q.5, 2026-05-19): all three commands are
now 4-domain. /rx-board + /rx-digest also
switched finance source from Lakshmi/rx/*.md filesystem
read to TradingV LOCAL postgres recommendations table
(D-046 contract). Degraded fallback to Lakshmi markdown mirror if
TradingV daemon unreachable. Per-domain auto-revive split across
writable surfaces (fitness Supabase UPDATE, learning markdown Edit,
finance read-only display-only).
Lovable RLS is permissive
Phase U/V shipped with USING (true) RLS policy on the
Supabase recommendations table — single-tenant assumption.
Multi-tenant safety deferred post-v1.x. Frontend + server both filter
by owner_user_id client-side. If the verocity app is
ever shared with another operator, this is the first thing to harden.
Nutrition zombie data — disposition channel unresolved
Supabase recommendations accepts domain='nutrition'
rows but no UI surface reads them (D-047 removed Lovable's nutrition
tab). If /rx-nutrition is ever wired in scaffold-to-live mode
without first re-routing storage or building a UI, the rows will sit
invisible in the table.
D-048 surfaced this as two blockers, not one: daily-log data
source (default Athena/daily_log.md per D-027, never confirmed)
AND disposition channel (no UI). Athena/rx/SPEC.md banner
now enumerates 4 resolution options:
- Markdown-only mirror of Ganesh learning pattern (Pragmatist recommendation)
- Supabase write + manual disposition (status quo, friction)
- Build local nutrition UI (Critic veto until ≥5 dispositioned recs with sustained ≥30% action-rate)
- Reverse D-047 + add Lovable nutrition tab (operator directive change)
Until operator picks, /rx-nutrition stays in scaffold
mode: reports state + decision menu, does NOT generate recs.
What the deep-retrieval & de-biasing program moved
The 2026-06-13 retrieval-depth program retired or mitigated several of the rot vectors this page used to list as open:
| Rot vector | Now |
|---|---|
| Substring hypothesis mislinking | MITIGATED — explicit linkage, substring is fallback-only |
| Confident-wrong from un-contradicted sources | MITIGATED — contradiction pass flags conflicts (governor-gated) |
| Fabricated / drifted citations | MITIGATED — deterministic citation verification at ingest |
| Self-influence flywheel (P&L credited to recs it caused) | MITIGATED — influenced trades excluded from predictive-lift |
New rot vectors the program introduced
Every fix has a cost. These are the new coupling/fault-lines to watch:
- Cross-repo payload contract. Deep results land in three stores under one shape — TradingV Postgres (
/v1/rx/deep), Supabase, and a learning markdown sidecar — plus the separate fitness-UI repo. A schema change must move all of them together. - Two identity spaces. The Supabase owner id (verocity auth uid) and the TradingV operator id are different values. A wrong-id write is invisible to RLS-scoped reads.
Landmine ledger — deferred debt with explicit triggers
Tracked in the rx repo's tech-debt log; each entry is fine at n=1 and has a named condition that should force the rework:
| Landmine | Trigger to fix |
|---|---|
| L1 · substring hypothesis-linkage fallback | remove at 2nd user OR >50 hypotheses |
| L2 · single hard-coded operator UUID | re-architect auth at 2nd user (the master n=2 trigger) |
| L3 · global (not per-cohort) thresholds | per-cohort + Bayesian smoother at 2nd user |
L4 · /rx-analyze lift/P&L math lives in the command, not the app | endpoint-ify when it drifts or needs unattended runs |
Where the doors-storage mapping actually lives The mapping {fitness: supabase, nutrition: supabase, finance: tradingv_local, learning: markdown} is not declared in any single yaml or json file. It is reconstructable only by reading D-045 + D-047 in rx-meta/DECISIONS-LOG.md plus the trading app's internal project docs. A maintainer wishing to verify "where does door X write?" must read those prose sources, then grep slash commands.
The closest thing to a canonical declaration is the facts inventory in
the project README.md (alongside this site) and the source-of-truth
table in AGENTS.md §3. If you change the mapping, update those
tables first — they are the only spots designed to be re-quoted.
How this site stays honest — the re-verification workflow
This explainer is documentation about other systems, so it rots the moment
a source repo changes. Rather than trusting the pages, every update runs a
re-verification pass. First, each upstream surface is independently
re-researched: the trading app (tables, ingest sources, endpoints), the
four door workspaces (rx artifacts and the decisions ledger), the
knowledge-vault (_domains.yaml, embedding pipeline, taxonomy),
and the Supabase schema behind the verocity app.
The findings then face an adversarial review from four deliberately opposed perspectives: a skeptic hunting factual errors, an architect hunting missing edges and failure modes, a user advocate checking clarity for non-technical readers, and a maintainer checking rot vectors and hardcoded coupling. Only pages whose facts actually changed get edited, every load-bearing fact keeps a pointer to its canonical source, and the source repos themselves are never touched from here — this site is additive only.
Source-of-truth quick reference
| Question | Where to look |
|---|---|
| Latest decisions? | rx-meta/DECISIONS-LOG.md (operator workspace) |
| Current phase status? | rx-meta/ROADMAP-v1_*.md |
| Domain registry? | knowledge-vault/_domains.yaml |
| TradingV tables? | TradingV repo migrations/ (Alembic SoT, not create_all) |
| TradingV module docs? | TradingV repo .claude/modules/ |
| Slash commands? | ~/.claude/commands/rx-*.md |
| Embedding config? | the vault indexer's config module (TradingV repo) |
| Chunking? | the vault indexer's chunking routine |
| Hybrid retrieval? | the vault indexer's hybrid / lexical / graph modules |
| Lovable schema? | Supabase schema introspection on the verocity project |
| Reconciler logic? | Step 0.5 + 0.7 of ~/.claude/commands/rx-<door>.md |
The deletions log — what got removed
Architectural simplifications worth remembering:
| What | When | Why |
|---|---|---|
| Lovable nutrition surface | D-047 · 2026-05-17 | Operator-directed scope reduction. Lovable = fitness-only. |
| Railway deploy | ADR 018 · 2026-05-17 | Cost + complexity not justified for single-operator app. Local-only since. |
| Auto-cron snooze revive | D-032 | Surprised operator with unexpected rec re-appearance. Made lazy. |
| BackendToggle component | 2026-05-18 cleanup | Vestigial from when Railway was an alt-backend. No purpose post-ADR-018. |
| Original D-045 (Lovable for nutrition) | Overridden by D-047 | D-045 still describes storage routing correctly; only the UI surface for nutrition was changed. |
Future v1.x candidates (per ROADMAP-v1_x) What is intentionally not in scope. Multi-operator support, fancier RLS, real-time cross-domain orchestration, scheduled auto-rec firing without command invocation, a v2 of the embedding model. Each of these has a v1.x or v2 placeholder but is deferred deliberately until the action-rate signal proves the system is worth investing in further.
/rx-meta— cross-domain meta-recommender (Phase O). Unlocks on ≥30% action-rate on every gated door plus ≥10 dispositioned recs total across domains (D-030).- Phase K scheduler — auto-trigger recs on threshold breaches without manual command invocation. Gated on action-rate health.
- Explicit hypothesis ↔ rec frontmatter linking (replaces substring heuristic).
- Nutrition rx generator wiring (Phase J.2) — depends on operator-chosen daily-log source.
- Learning corpus ingest at scale — depends on operator drop of URLs.