This file is the ubiquitous language for the Investor Flow project. It is a glossary, not a spec. Updated inline as terms are resolved during design (per the `domain-modeling` skill).
**Status of what is built vs pending** lives in `docs/FUNCTIONAL_DESIGN.md` and `docs/TECH_DESIGN.md` (audited 2026-08-18). Do not treat this glossary as a build checklist.
**Investor Flow** — A multi-tenant investment **management** workbench for retail investors (positions, risk, market awareness, decision process). Helps users become better at awareness and risk management while managing - not a course/education app. Legal voice: educational publisher (ADR-0007). Local-first: Next SPA + Node/SQLite backend, Docker Compose. Voice: convex in process, soft in presentation. **Workspace density** (`focused` | `standard` | `full`) adapts nav and research detail from a short setup interview.
**Primary Rule — Education, not investment advice.** Investor Flow is an educational research terminal, not an investment adviser. It teaches *how a disciplined investor reasons* about a position; it never says "buy/sell/hold this." Every recommendation is a **consideration + a question**. RiskEngine `recommendedActions` are reworded (cut_to_cash → consider_reducing_position; trim_cluster → consider_rebalancing_cluster). SizingEngine outputs *math*, not instructions. Journal asks "what's your reasoning?" Alerts say "something changed," not "action needed." Every report closes with: *"Educational analysis, not investment advice. Verify the underlying data; you are responsible for your own decisions."* Legal posture: educational publisher. Formalized in ADR-0007. Every LLM prompt template and UI string reviewed against this rule ("Primary Rule lint"). When this conflicts with another principle, this wins.
**Analyst Voice** — The single house voice for every LLM Signal Summary, explainer, and alert. 70/25 blend of Mike Alfred (Alpine Fox LP — concentrated value conviction, ownership posture, plain-spoken directness) and Stanley Druckenmiller (macro-regime adaptation, asymmetric convexity). Rules: process over prediction; concentration posture; macro + company twin-lens; honest about uncertainty; P6 plain English; cite every claim to a cached source; confident when conviction exists, silent when it doesn't. Formalized in ADR-0005.
**P6 — Accessible-but-authored voice.** Core UX principle. Every user-facing string reads as plain English to a non-finance reader while staying professional. No orphan jargon (every term glossed in-screen); no baby talk; no unexplained acronyms. Complexity level adapts depth, not voice.
## Strategy & Sizing
**Strategy** — A named bundle of { Regime gate, Setup, Risk Policy }, reusable across symbols. A TradePlan is an instance of a Strategy applied to a symbol at a time.
**Regime** — A classification of market state (trending-up / trending-down / range-bound) over an index/timeframe, used to gate trading posture and sizing.
**Setup** — A parameterized, repeatable entry/exit checklist applied to a symbol situation.
**Risk Policy** — Sizing + stop-width + defined-risk rules applied when a setup fires.
**Screener** — A tool that evaluates a universe of symbols against one or more Strategies' entry conditions and outputs matches. (A screener run is a read-only backtest at "now".)
**Backtest** — Running a Strategy against cached historical OHLCV to compute performance. Cache-only; no live calls. Same engine as Screener.
**Position Sizing** — The function producing share quantity given a Strategy, risk%, stop, account, live portfolio, and regime. Multi-layered (Layers 0–4).
**Risk Per Trade** — Dollars an account is willing to lose if a plan's stop is hit, before any size is computed. Default 1% for beginners.
**Conviction Tier** — A_STAR / A / B / C — the user-graded quality of a setup; multiplies the base risk fraction (×3 / ×2 / ×1 / ×0.5). Locked at lower tiers until per-tier win-rate statistics justify unlocking.
**Sizing Unlock** — A workflow state: complexity-tier elevation earned by accumulating profitable trades at a sub-tier (20 profitable B → unlock A; 10 profitable A → unlock A_STAR). Tunable per-user.
**Macro Regime Gate** — When regime trending-down = ×0.5 size; ranging = no A_STAR; trending-up = normal + A_STAR unlocked. Default: auto-cap with one-tap override requiring a written reason.
**Correlation Cluster** — A group of holdings sharing a single macro/factor driver (e.g., all BTC miners). Aggregated exposure capped; beginners get hard caps, intermediates get warnings.
## Institutional & Insider
**Quarter** (institutional module) — The reported calendar quarter a 13F snapshot is *as of*. Buy-zone/sell-zone estimates reconstruct institutional transaction likelihood within that quarter from the snapshot diff + volume-weighted price action.
**Institutional Footprint** — Per-symbol combined ownership picture from all four SEC forms (13F, 13D, 13G, Form 4), with every owner row classified by holder type.
**Holder Class** — One of: `Passive Index`, `Activist`, `Active Conviction`, `Market-maker/Hedger`, `Insider`. Inferred from which SEC form(s) filed + CIK entity metadata (SIC codes).
**Net Active Conviction Δ** — Per-symbol QoQ share change summed across Active Conviction + Activist classes only. Excludes passive index and MM/hedger noise. The ranked signal on the dashboard.
**Holder Snapshot Diff** — Quarter-over-quarter Δ per institution per symbol, derived from consecutive 13F filings.
**Insider Transaction** — A single Form 4 transaction by an officer, director, or 10%+ holder. Classified: Informed Buy / Informed Sell / Routine.
**Informed Buy** — Open-market buy (code P) NOT under a Rule 10b5-1 plan. Highest-signal insider bull.
**Informed Sell** — Open-market sell (code S) NOT under 10b5-1. Negative signal; alert by default.
**Routine Insider Transaction** — Any Form 4 transaction under 10b5-1, OR an option exercise (M), grant (A), or vesting event. Pre-scheduled/compensation-driven; low signal; hidden by default for beginners.
**Buy-Zone Estimate** — Volume-weighted price band during a quarter in which an institution *likely* accumulated/reduced. An estimate, always tagged "estimated" in the UI.
**Insider Activity Stream** — Real-time per-symbol ledger of Form 4 filings, classified, with Informed events surfaced first and alertable. Own module (M5), separate from quarterly snapshot (M4).
## Sector Rotation
**Sector Rotation** — Movement of capital between market sectors. The module surfaces both realized (RS-rank reshuffle over N weeks) and incipient (early RS-slope turn + breadth thrust before price moves) rotation.
**Rotation Phase** — A label on detected rotation: Accumulation → Expansion → Distribution → Markdown, with a confidence score.
**Rotation Signal History** — Every incipient rotation signal is logged and later resolved as Real or False-alarm. Two-stage resolution (γ): price follow-through confirms first (within N=4 weeks, deterministic); institutional flow confirms later (quarter-end, durable). Enables "which signal types were reliable" learning.
## Ticker
**Ticker Kind** — `equity` | `crypto` | `etf` | `index`. Gates which modules apply (e.g., crypto excluded from SEC/13F/insider modules). BTC kept for price/sentiment only.
**Symbol** — A ticker as a first-class identity (e.g., IREN). Carries a `Ticker Kind`, display name, sector/industry, exchange, and — for equities — an **Issuer CIK**. The canonical record is the `symbols` table; it is what autocomplete resolves against when a user adds a symbol to a watchlist or searches at the top.
**Issuer** — The company a Symbol represents (e.g., the company behind IREN). Identified by the SEC **Issuer CIK** (the company's own SEC identity — files its own 10-Ks, insider Form 4s, 13D/G). Distinct from a **Filer CIK**, which identifies a fund that files 13Fs. Same CIK identifier space, two roles: issuer = the company the symbol stands for; filer = the fund that reports holdings.
**Symbol Search Index** — The autocomplete corpus for adding symbols and top-bar search. Sources: the `symbols` table (issuer CIK, name, sector, ticker kind) joined with fund-holdings edges (`fund_position_records`) so a result can surface "also held by [Tracked Fund]" from the fund side. Local-first per ADR-0009: no live vendor search on the request path. **Scope: search results are symbol-only** — the fund-holdings edge is NOT shown inline in autocomplete; it surfaces on the symbol's overview page after the symbol is added.
**Add-Symbol Resolve Rule** — How watchlist add behaves when a typed string does/doesn't match the Symbol Search Index (hybrid): a known-symbol match adds instantly with confidence; an unmatched string is a **soft-block** — the app asks "this symbol isn't in the SEC registry — add anyway?" before adding, then hydrates metadata in the background via the adapter queue (quote, issuer CIK if findable). The row appears immediately, marked "resolving…" until hydration lands. Strictness is a question, not a wall.
**Fund-Holdings Strip** — The symbol-page section answering "who holds this?" Two tiers: **(1) tracked funds first** — the M21 `fund_position_records` edge, each with its weight in the fund's disclosed book (e.g., "Alpine Fox — 3.2% of book"); **(2) all institutions second** — an expandable "N other institutions report holding this (13F)" line sourced from the shared `institution_filings` cache (M4). Tier 1 is curated and deliberate; tier 2 is broad and noisy — order encodes trust.
**Issuer CIK Seed (company_tickers.json)** — The SEC's `company_tickers.json` bulk file (https://www.sec.gov/files/company_tickers.json) is the canonical seed for the Symbol Search Index: ~12k+ US tickers, each paired with issuer CIK, name, and exchange. SEC overwrites the file **in place daily** (start of trading day, ~5:30am ET; no historical versions). Refresh cadence = once per trading day, scheduled, never on the request path (ADR-0009 stale-while-revalidate pattern). Materialization = a scheduled queue job (`sec-company-tickers` source kind) that upserts into the `symbols` table.
**Symbol-Metadata Merge Policy** — Two writers on the `symbols` table, two ownership domains, no overwrite war. The SEC seed **fills** only what it's authoritative for: `cik`, `name`, `exchange`. It **never touches** yfinance-hydrated `sector`, `industry`, `peers` (absent from the SEC file), and **never downgrades** an existing `ticker_kind` (etf/crypto/index preserved — kind gates module applicability). Rows absent from the SEC file (crypto, some ETFs, indexes) are **never purged** — the SEC universe is a subset, not the whole. Background hydration (Q1) owns classification/descriptive metadata; the SEC seed owns issuer identity.
**Filter Screener (M15a)** — A TradingView/Finviz-style screener: user writes ad-hoc filter expressions (descriptive, technical, fundamental, events, ownership, sentiment) over a universe; outputs matching symbols with "why matched." Beginner-immediate. No Strategy required. Saved filter sets are per-user (Tier C). Not backtested. Universe: tiered (watchlist first, opt-in broader scan scoped by sector).
**Strategy Screener (M15b)** — A screener that evaluates a chosen Strategy bundle's entry conditions across a universe; outputs symbols where the Strategy fires, with conviction-strength (how many entry conditions true). Backtestable. Requires an authored Strategy (gated by Conviction Tier unlocks). Output: symbol + which conditions fired + one-tap into Symbol Overview workbench.
**UniverseEvaluator** — Shared deep module iterating a symbol universe and applying a pure predicate (a compiled filter expression OR a Strategy's entry conditions) against cached data. Powers both M15a (filter predicate) and M15b (Strategy predicate). One interface, two callers.
Screener output policy (both modules): symbol + "why matched" + one-tap "open in workbench" (drop symbol into Symbol Overview). The screener shortens time-to-conviction; it is never the final answer.
## Options Convexity Sleeve (M17)
**Options Convexity Sleeve (M17)** — A portfolio module applying a small defined-risk options overlay to a core holding — for income (covered calls), cheaper entry (cash-secured puts), downside insurance (protective puts/collars), or leveraged thesis (long LEAPS). Never standalone directional. (Research-grounded: Spitznagel/Universa tail-hedging, Pabrai cash-secured entry, Ackman rate-hedge overlay, Druckenmiller cheap-convexity, Buffett index-put seller.)
**Sleeve Risk Budget** — Per-thesis combined budget for stock + options risk (e.g. 1–5% of portfolio). SizingEngine enforces the combined ceiling so options can't quietly swell.
**Convexity Posture** — A user's options advancement state: `Off → Covered Income → Cash-Secured Entry → Insurance Sleeve → LEAPS Conviction`. Unlocks progressively by Sizing Unlock (mirrors Conviction Tier). Default `Off` (Alfred: "I don't think most people should use options tbh").
**Defined-Risk Only** — Hard module constraint: strategies with unbounded loss (naked short calls, naked short straddles, undefined-risk structures) are physically blocked. Beginner guardrail; never disabled for beginners.
**Tail Convexity** — A small portfolio sleeve (~1–3%/yr) of long-dated deep-OTM puts on broad indices OR a correlation cluster (Spitznagel/Universa model). Pays small premium most months, asymmetric payout in tail events — *insurance*, not speculation.
**IV Regime Gate (within M17)** — Modulates allowed overlays by IV Percentile: covered calls when IV high (juicy premium); protective puts / LEAPS when IV low (cheap insurance). Never buy convexity when it's expensive.
**Tracked Fund** — A specific fund (e.g., Alpine Fox LLC) the operator follows fund-first: the inverse of the symbol-first Institutional module. Identified by CIK for SEC data (13F) and by the manager's X handle(s) for the live channel. The fund and the person are distinct entities: the 13F is filed by the fund (CIK); X posts come from the manager. Two channels, two authorities, two latencies — official but stale (13F) vs live but self-reported (X).
**13F Record** — A single SEC-confirmed holding row for a tracked fund: CIK, symbol, shares, market value, reported quarter. Quarterly + ~45-day filing lag; *as of* the quarter end. Shows drift, not decision. Reuses the shared `institution_filings` cache (ADR-0004). _Avoid_: holding (ambiguous across channels).
**Position Capture** — A self-reported snapshot of the fund's *current total position* in one ticker, with actual numbers: total shares, market value, and **cost basis**. Posted by the manager on X (typically as a screenshot); recorded with post date + evidence link (tweet URL). Dated state on the position's timeline — it supersedes earlier captures for the current view but never overwrites history. _Avoid_: screenshot (implementation detail), position update (ambiguous).
**Trade Claim** — An X post stating a position *delta* with real numbers ("added n shares at x average price"). Supplementary color, never authoritative state; recorded as a dated delta that should reconcile with the next Position Capture (prev total + delta ≈ new total; avg-cost math must close).
**Cost Basis** — The average cost per share shown in a Position Capture. The decision-level measure (what the manager deployed), contrasted with market value which is drift. What makes a fund's *construction* readable through captures and invisible in 13Fs alone.
**Live Book** — The current-state view of a Tracked Fund's holdings: the most recent record per position, mixing 13F Records and Position Captures, each labeled with its source and as-of date. "Estimated/live" for captures, "SEC-confirmed (quarter-end)" for 13F.
**X Post Classes (fund feed)** — Every manager post splits into exactly two classes: **Position Captures / Trade Claims** (actual numbers → become records) and **commentary** (thesis talk, macro takes, no numbers → never a record, no matter how strongly worded). Classification is per-post; the app already LLM-classifies posts (sentiment) so there's a precedent.
**Disclosed Book** — The fund's visible holdings: 13F Records + Position Captures. Weights are computed over the disclosed book only — cash, hedges, and non-disclosed assets are unknown and labeled as such. _Avoid_: portfolio (implies the whole fund, which we can't see).
**Mirror Portfolio** — The module's core job: the user's stated goal of replicating a Tracked Fund's book. The target = the fund's Disclosed Book expressed as weights; applied to the user's own equity it answers what to buy, when (the X edge: captures are live, 13F lags ~45 days), and how many shares to match each weight. Per-user math over shared fund data; never advice (ADR-0007 line: "to match this weight, buy N shares" is a calculation for a user-stated goal, not a recommendation). Whole-book scope: the mirror converges the user's entire portfolio to the fund's weights, scaled to a user-entered capital base (suggested default ~$200k; accepts ~$20k accounts). The fund's AUM never enters the math — only the user's base does.
**Mirror Floor** — The minimum position threshold in the Practical Mirror: positions below ~$500 or ~0.5% weight (whichever is larger) are excluded from the mirror and reported as one "excluded (below minimum)" line. Fractional shares allowed but rounded to a sensible tick. The floor is a setup choice, shown honestly.
**Mirror Target Rule** — The mirror's target per position = the most recent record by as-of date, regardless of source. A Feb capture beats a Dec 31 13F; a Mar 31 13F beats a Feb capture. Captures and 13F Records compete on recency, not authority (no badges, no verdicts — option 2 reconciliation).
**Mirror Diff** — The delta between the fund's current target weights and the user's current holdings, recomputed on every new 13F Record or Position Capture. The "what to trade to stay matched" view: position, weight change, shares to buy/sell.
**Fund Performance (mirror)** — The disclosed book marked to market (equity curve, estimated from disclosed holdings) plus position-level unrealized P&L vs Cost Basis from captures. Dataroma-style returns with the unique cost-basis anchor nobody else has. Always labeled "estimated from disclosed holdings."
**Manager Insider Activity** — Form 4 transactions filed by the manager personally (as officer/director/10% holder), cross-referenced by insider_name against the shared `insider_transactions` cache. Surfaced on the fund page as a conviction-context strip ("fund holds IREN; manager is a director; latest Form 4: informed buy"), alongside 13D/13G events by the fund's CIK. **Never part of the Disclosed Book and never moves the mirror** — the fund's book changes only on fund records (13F Records, Position Captures); the manager's personal account is not the fund's book.
**Macro Module (M18)** — Fourth pillar module: calendar of high-impact macro events (M18a), current-regime classifier (M18b), portfolio-impact commentary (M18c), and regime history (M18d). The Druckenmiller 25% lens given dedicated surface. Reads macro + connects to portfolio; never recommends a macro trade (the Alfred caution extends to macro-trading). Leaves action to Conviction Tier + Convexity Posture gates.
**Macro Regime** — A label classified by M18b (trending-up / trending-down / range-bound / structurally-shifting) from yield curve, inflation, rate path, liquidity, breadth. Consumed by the Macro Regime Gate (SizingEngine Layer 4). M18b is the classifier the gate depends on.
**Portfolio Impact Commentary** — LLM-generated (Druckenmiller lens), two-horizon: short-term reaction risk (per-event, per-correlation-cluster, with historical averages + sample size + disclaimer, never a forecast) and long-term structural read (regime-shift framing). Cites M18 regime + the user's actual holdings. Always on (matches Analyst Voice "always on" decision).
**Confluence Signal Engine** — The multi-axis evidence aggregator that produces a per-symbol "picture quality" (strong/moderate/weak-bullish, mixed, weak/moderate/strong-bearish, sparse) from34 independently-evaluable slots across 6 families: technical (15), institutional (5), macro (5), seasonal (5), flows (3), sentiment (1). ADR-0007: describes the picture, never recommends action. ADR-0012.
**Slot** — A named, independently-evaluable check whose firing state contributes bullish or bearish evidence to a confluence rack. Each slot has a `SlotBody` (bull / bear / exit), a `SlotFamily`, a `SlotGranularity` (1d / 1wk), and an ADR-safe `explain` note (evidence sentence, never a directive). The 34-slot catalog is defined in `confluenceSlots.ts`.
**Rack** — A named subset of the 34 slots that evaluates a symbol's confluence. Can be a system preset (Full Confluence, Technical Momentum, Macro+Flows+Sentiment) or user-created. A rack evaluation produces the redundancy-discounted evidence totals and picture quality label.
**Redundancy Group** — A set of slots that measure the same underlying condition (e.g. goldenCross + trendAlignment + pullbackToEMA21 all measure trend state). Evidence within a group decays geometrically (1 + 0.5 + 0.25 ...) so correlated signals count once, not triple. Defined in `confluenceLibrary.ts`.
**Picture Quality** — The evidence-based label for a symbol's confluence: strong/moderate/weak-bullish, mixed, weak/moderate/strong-bearish, sparse. Labeled from redundancy-discounted evidence totals using direction ratio (0.6) and magnitude thresholds (strong ≥ 4.0, moderate ≥ 2.0, sparse < 1.0 total evidence).
**CandleProvider** — The seam that resolves a symbol's candles per-granularity (1d/1wk) from the cache, with a realtime fold-in of the freshest live quote. Used by confluence evaluators instead of `cache.get` inline so a future realtime/replay source can slot in without touching slot logic. `candleProvider.ts`.
**Signal History** — The closed-loop log: every slot fire is recorded with the as-of date, rack, and picture quality. A resolver later checks whether price moved the expected direction over 4 weeks (bull → up, bear/exit → down). Verdicts: `real` (confirmed), `false_alarm`, or `deferred` (not enough forward bars). Per-slot reliability weights (0.5–1.25) allow the rack to self-tune.
**Reliability Weight** — A 0.5–1.25 multiplier applied to a slot's evidence based on its historical follow-through: ≥8 resolved fires at ≥90% hit rate → 1.25×; <2 resolved or ≤50% → 0.5×; thin sample → 0.75×. The rack can multiply per-slot evidence by this to self-tune.
**Confluence Change** — A detected shift in picture quality tier or net evidence (≥ 0.35 shift). Driven by the `confluence_change` alert producer. Throttled to 5/hr. ADR-0007 framing: "the picture has changed," never "act now."
**Confluence Universe** — The 15 research symbols + SPY benchmark that the confluence engine tracks: PLTR, NVDA, AMD, AAPL, MSFT, SMH, XOM, JPM, UNH, COST, AMZN, CAT, LMT, LIN, NEE. Pinned into the demand set on startup.
**Regime History** — Timeline of regime classifications over time; cross-references Rotation Signal History. Pedagogy for "did we detect the shift correctly" — beginner learns which classifier calls were early vs whipsawed.
## LLM Data Provenance (ADR-0006)
**ornith** — The default LLM provider for Investor Flow: a remote-hosted, operator-owned, OpenAI-compatible REST endpoint. Configured `is_local=true` in `llm_providers` so it serves both public and sensitive features (ADR-0006 Data-Classification Gate). Env vars `ORNITH_LLM_URL` + `ORNITH_LLM_API_KEY` injected via Docker Compose secrets. Formalized in ADR-0008. The provider itself is pluggable; `ornith` is the v1 default, not a hard dependency.
**LLM Data Provenance** — Three hard constraints enforcing no-training-on-user-data: (1) Production LLM Gateway defaults to a **local OpenAI-compatible endpoint**; non-local providers require explicit operator override + documented provenance review. (2) **Sensitive user data** (portfolio positions, trade plans, journal, SEC content, sentiment annotations, saved posts, anything tagged ownerId or Tier C) is **never routed through external LLM providers** by code-level data-classification gate, not a runtime toggle. (3) **Developer conduct**: never paste live user-data into external AI-assistant prompts during the build; use fixtures/synthetic data only.
**Local-first default** — The Gateway's `baseURL` defaults to a local endpoint (Ollama/vLLM on host or LAN); the only provider config loaded by default. "Local" = `localhost`, `127.0.0.1`, `::1`, or `LOCAL_LLM_SUBNETS` env override.
**Data-Classification Gate** — `LLMGateway.classifyPayload(payload): 'public_safe' | 'sensitive'` runs before any provider dispatch. Sensitive payloads routed to non-local providers throw `SensitiveDataBlockedError` and never leave the host. A code-level guarantee, tested via property tests over a fuzz corpus.
## Ticker-Data Dedupe (Architectural Pattern)
**Content-Addressed Caching** — All fetched market data is cached by a content-addressed key (e.g., `yfinance:quote:IREN`). Two users fetching the same symbol collapse to the same row; duplicates don't happen by construction. Tier A tables (price/candles/options/filings/13F) have no ownerId and are shared.
**Demand Set** — The set of symbols that currently have ≥1 user tracking them (watchlist ∪ open portfolio holdings). The adapter queue only schedules fetches for symbols in the demand set — zero wasted bandwidth on untracked symbols. Cost scales with the *breadth of the demand set*, not user count (a million users all tracking NVDA = still one NVDA fetch per staleness window).
**Refcount** — Per-symbol demand counter, bumped +1 when a user tracks the symbol, −1 when they untrack. Refcount → 0 halts live/sentiment refresh for that symbol; historical immutable data (backtest OHLCV, SEC filings) stays cached regardless because backtests/filings need it forever.
**Stale-While-Revalidate** — The SPA reads from cache instantly and the backend silently schedules a background refresh if the row is past its staleness window — the user never blocks on a live fetch. Duplicate concurrent cache-misses for the same key collapse to ONE fetch (multi-tenant dedupe per ADR-0004).
**Rate-Limit-First Data Plane (ADR-0009)** — Every vendor (Yahoo, X, FRED, SEC, Reddit) has a short rate limit. Design for that: request path serves cache / static first; only `AdapterQueue` does outbound fetches; a 429 cools down the *entire source* for minutes (not a 2s job retry); demand set bounds work; stale UI beats empty UI that thrash-retries.
## P7 — Visualizations teach mechanics, never decorate outcomes
**P7** — Core UX principle (added alongside P6). Every visualization makes a mechanical relationship more *legible*, never more *exciting*. Visuals can teach or manipulate (Robinhood's confetti SEC fine is the cautionary tale). The four guardrails:
- **G1 — Teach the mechanic, don't decorate the outcome.** A chart showing *where Citadel accumulated within the quarterly price band* teaches; a "+15%!" bouncing number celebrates. Alfred-lean voice explains mechanics, never celebrates results.
- **G2 — Every chart has a one-line "what this tells you."** No naked visualization. Each chart/heatmap/payoff diagram carries a P6 plain-English caption written at design time. If we can't write the lesson, the viz is decoration, not a feature — drop it.
- **G3 — Color-blind / accessibility-safe by default.** Red/green for P/L is dangerous (8% of men). Use **shape + color + label** triads: institutional adds = up-triangles in blue, reduces = down-triangles in amber, text labels always present. Recharts/visx support custom shapes natively.
- **G4 — Annotated data viz over abstract 仪表盘.** The LLM-generated Signal Summary produces **annotated chart overlays** — summary text has chart positions tagged. One annotated story, not 5 detached widgets.
## Anti-gamification rules (locked)
Explicit "do not build" list — written down so the build doesn't accidentally Robinhood itself:
- No trade-animation confetti / win-streak badges / "you did it!" celebrations — Robinhood was SEC-fined for this.
- No 3D / decorative gauges — chart-porn, no mechanic taught.
- No real-time candle-minute flickering — encourages trader-brain, not investor-brain. Daily candle with a steady quote line is enough.
- No outcome-celebration visuals. Sizing/backtest viz shows mechanics (drawdown is more important than win rate), not trophies.
## Canonical visualizations (locked — the curated 10)
Each is curated at design time with its one-line lesson (G2). Not an open-ended viz library.
1.**Annotated Price Chart** — candles + Form 4 insider buy ▲ markers + institutional buy-zone shaded band + macro event markers + key levels overlaid. *Lesson: prices move WITH insiders/institutions/events, never alone.*
2.**Sector Rotation Heatmap** — sectors × weeks grid, color = RS rank, cells pulse on phase transitions. *Lesson: money rotates between sectors; early signs are subtle.*
3.**Rotation Phase Timeline** — horizontal stream of Accumulation→Expansion→Distribution→Markdown markers. *Lesson: rotation is a phase sequence, not an instant.*
4.**Options Payoff Diagram** — today + at-expiry + early curves, max loss/gain shaded, breakeven marker. *Lesson: an option position is a SHAPE not a bet; defined-risk is visibly bounded.*
5.**Institutional Footprint Stacked Bar** — per-symbol holder-% by Holder Class, color-coded (MM/hedger vs Active Conviction visually distinct). *Lesson: not all ownership is conviction.*
6.**QoQ Institutional Δ Chart** — per-filer bars over a price-range overlay at the band they likely transacted at. *Lesson: institutions move over a quarter, on a price band.*
7.**Correlation Cluster Treemap** — your holdings grouped by factor driver; cluster size = exposure $. *Lesson: 5 holdings != 5 bets; factor risk (the 2008 lesson).*
8.**Sizing Decision Tree** — account → risk-per-trade → tier multiplier → position size, animated as you change a Conviction Tier. *Lesson: sizing isn't a guess; it cascades from rules you earned.*
9.**Strategy Backtest Equity Curve + Drawdown overlay** — P/L line with drawdown under it; trade dots are entry+exit. *Lesson: worst pain matters more than win rate.*
10.**Annotated Institutional Event Card** — one chart with text callouts at each event point + the one-paragraph Analyst Voice summary alongside. *Lesson: many data streams → one coherent story. THE beginner viz.*
## M19 — Mobile Monitor (companion surface, not mobile-first)
**Mobile Monitor (M19)** — Separate thin client reading the same Bun backend + SQLite cache + adapter queue + LLM Gateway as the desktop workbench. For job A (passive monitoring: alerts, P/L glance, per-symbol story) NOT job B (active research: backtests, multi-panel cross-reference, screener, strategy authoring). Read-mostly; limited authoring (add to watchlist, ack alert, save post). Native is a later phase; v1 = Next responsive route, not React Native. Built second, after the desktop workbench.
**Two-job split** — Investor Flow serves two jobs at two home surfaces: (A) passive monitoring on the go = mobile phone, M19; (B) active research at a desk = desktop/laptop, M1–M18 workbench. One backend, two co-equal client surfaces. Going mobile-first would force job A's surface on job B (Robinhood's bet); the depth that justifies the product dies.into tabs. Build desktop workbench first; thin mobile companion second shares all backend work (refcounted shared cache means mobile is a second client, not a second product). ~30% more frontend, 0% more backend.
## Two-Axis Investment Model (Fundamental × Technical)
**Fundamental Thesis** — The written WHY of an investment: what to own + invalidation criteria. Tracked over time (`intact` / `weakening` / `broken`). Broken thesis = exit regardless of TA. Process-grounded: Alfred's BKKT entry was 8 months of fundamental thesis-building before deployment.
**Entry Confluence Rack** — The accumulating WHEN: a structured checklist of technical confluences. Each lit = +1; more lit = better entry quality. Generalizes the old journal's `confluenceCount` into a structured, named, trackable rack. A user authors the Rack per-Strategy by pulling from the Confluence Library.
**Two-Axis Posture** — Every investment has two independent axes: fundamental conviction (Conviction Tier) × technical entry (Confluence Rack). High conviction + bad entry = WAIT (never "buy like an idiot"). The SizingEngine enforces the posture matrix as a hard guardrail. Override requires one-tap + written reason (mirrors Macro Regime Gate).
**Entry Confluence Rack (4-factor default)**:
- **A. Trend alignment** — price > EMA200, EMA21 > EMA50, higher-highs/lows. +1 when all 3 hold.
- **B. Pullback maturity** — recent low near EMA21 or a key level + volume dryup on the dip. +1 when both.
**Confluence Slot** — A single authored predicate `lit(symbol, cachedData) → bool`. Pulled from the Confluence Library. Rack = collection of slots. Default Rack = 4 slots (beginner); extendable to 6+ (advanced).
**Confluence Library** — Registry of named parameterizable slot templates: `trendAlignment`, `pullbackToEMA21`, `catalystProximity`, `riskBoundCoherence`, `sma200w` (200-week SMA proximity), `rsImproving`, `breadthThrust`, `insiderInformed30d`, `instNetActivePositive`, `ivPercentileLow`, etc. Long-horizon SMAs (e.g., 200-week) measure multi-year holder cost basis — strong *thesis support*, can also be authored as *entry slots* when price is within X% of the level.
**Redundancy Awareness** — When multiple lit slots measure the same underlying signal (e.g., 21-EMA > 50-EMA AND price > EMA200 AND price > 200-day SMA in a persistent uptrend), the app tags them "redundant — counts as one signal." Analyst Voice explains why; the user keeps/removes at will. Adding indicators doesn't necessarily improve entries; redundancy adds noise.
**Deployment Schedule** — How capacity (Conviction-Tier-sized) is entered over time/space, gated by Confluence Rack accumulation. Replaces one-shot entry with corridor scale-in (Alfred's May 15-18 four-day deployment at a price corridor). Beginner-default: "deploy 40% at Rack≥3; deploy remaining 60% at Rack≥4 OR price revisits buy-zone / EMA21."
**Thesis Monitoring** (autonomous, 3 layers):
- **L1 — Per-holding**: every relevant event for that symbol cross-references the user's stated invalidation criteria; fires intact/weakening/broken per position.
Each independently alertable; surfaces on M1 (L1), M10 portfolio dashboard (L2), M18 macro module (L3); M19 mobile shows all three in priority order. Not a forecast engine — never predicts returns; only translates stated invalidation criteria into alerts when matching events arrive. L1 runs via CacheRepository reads + LLM Gateway over local-only provider per ADR-0006 (thesis content = sensitive user data).
**M20 Risk Posture** — Single unified risk-picture surface. The "where you see your complete risk picture + what to cut" panel. Curated visualizations under P7 (drawdown gauge is NOT a decorative gauge — teaches the mechanic: drawdown-vs-tolerance-by-style-fit), recommendedActions with cited inputs. Prominent on M19 mobile.
### The 6 risk primitives (locked dictionary)
**Max Drawdown Tolerance** — Per-user $/% threshold stated at onboarding. Hitting it → halt_new_entries (24h cooldown + L1 thesis re-evaluation). The Soros circuit breaker as user policy.
**Total Risk Capacity** — Max sum of open-position risk if all stops hit (beginner default 5% of equity). SizingEngine enforces per-position; RiskEngine enforces aggregate.
**Correlation Cluster Cap** — Max % equity in one factor driver (beginner default 25%; 40% intermediate). SizingEngine Layer 3 enforces at entry; RiskEngine surfaces breach across whole book.
**Asymmetry Score** — Portfolio-weighted reward-to-risk across open positions (stated target & stop). <1.0 → warning ("your trades are sized wrong on average — losing over time even winning some"). Soros's principle in a number; pedagogically powerful but confronting.
**Regime Risk Posture** — Portfolio-wide cash recommendation by regime-vs-style fit (aligned/misaligned/hostile). Trending-up → ≤20% cash; structurally-shifting → ≥50% cash + halt fresh entries if no thesis resists the new regime. Druckenmiller's "cut risk when regime turns before losses prove it."
**Thesis-Broken Exit Rule** — L1/L2/L3 thesis monitor flag = broken → push-alert (mobile) + popup (desktop) + immediate exit recommendation with cited event. One-tap-override-with-written-reason; never silently held. The Alfred discipline.
### Default risk caps (by complexity)
- Beginner: total risk = 5% of equity; correlation cap = 25%; halt drawdown = -20%; cooldown = 24h.
- Intermediate: 10% / 40% / -30% / 12h.
- Advanced: authorable per user.
## Derisking (the asymmetric-management discipline)
**Derisking Strategy Library (6 strategies)** — Derisking is asymmetric: winning trades have flexibility (scale out, trail, insure); losing trades have only cut (stop or thesis-broken). The app asks "winning or losing?" before suggesting a derisk path. Default derisk for A_STAR conviction winner = choice between scale-out (SRxTrades-style selling) and protect-with-collar (Spitznagel-style insuring).
1.**Scale-out at targets** — trim 25%/target + breakeven-stop-after-first-trim + runners with trailing stop. SRxTrades mechanic.
2.**Stop-trail up** — trail with EMA21 (swing) or EMA50 (trend); exit fully below EMA50 close. Sunil mechanic.
3.**Thesis-based partial derisk** — trim by thesis-status: intact→hold full; weakening→trim 25-33%; broken→exit remaining. L1/L2/L3-driven. Alfred mechanic.
4.**Options-protected hold (collar)** — buy protective put below current price (locks downside, keeps upside) + covered call above (collar) to fund the put. The Spitznagel/Universa convex path: don't sell, insure. For convicted winners where you want downside bounded but thesis intact.
5.**Regime-cut derisk** — sell down to target cash posture (e.g. 50%); portfolio-wide not one-at-a-time. RiskEngine recommendedCashPct.
6.**Correlation-driven derisk** — trim the cluster not the winner; reduce biggest cluster-cap violator.
**Exit Strategy** — First-class field on `Strategy` (alongside Setup). Previously we specified entries but not exits. Now: Exit Strategy = the derisk + exit logic authored per-Strategy, sourced from the Derisking Strategy Library (6 primitives above, default per complexity).
**Two-Axis Derisking** — The app considers BOTH thesis-status AND price-momentum before suggesting. Winning + thesis intact → collar or scale-out; winning + thesis weakening → scale-out + tighter •••; losing → cut only (never average down or sell puts against a loser; those are trader-paths beginners lose on, not in our app). LLM Analyst Voice distinguishes: "Thesis still intact at A-STAR? The collar protects downside while keeping your winners. Thesis weakening? Scale out — don't insure a name you might not want."
++**Problem:** The `session-context-loader` skill installed globally via `npx skills add` doesn't auto-trigger on OMP session start. Even though SKILL.md is in `~/.pi/agent/skills/session-start/SKILL.md`, OMP only loads AGENTS.md files from project directories into context — it doesn't scan and invoke installed skills automatically.
++**Investigation findings:**
+- Confirmed skill file exists at both `~/.pi/agent/skills/session-start/SKILL.md` (direct copy) and `~/.agents/skills/session-start/SKILL.md` (symlink target)
+- Verified frontmatter format matches working skills like anti-sleep (name + description fields identical)
+- Discovered Pi/Claude Code only loads ~45 of 60+ installed skills into available tools list — session-start is in the "not loaded" group along with ~15 others
+- OMP's context injection mechanism: reads AGENTS.md from project directory and injects it into `<context>` block automatically. Skills are separate — they're available as tools but not auto-triggered.
++**Resolution:** Manual skill invocation instead of inlining session-start logic into project-specific AGENTS.md files (which wouldn't be generic anyway). Updated `~/Documents/investor-flow/AGENTS.md` to remove conflicting instructions about reading wiki page directly, replaced with brief note that session-start skill handles context loading.
++**Key takeaway:** OMP loads AGENTS.md automatically for project-specific instructions, but does NOT auto-trigger skills from ~/.pi/agent/skills/ — requires manual invocation or explicit user request. npx skills add puts files in right place but doesn't change OMP's discovery behavior.