# Instrument Catalog + Manual Add Workflow

Use this reference when building or extending manual portfolio entry, provider-symbol mapping, and dashboard search/add flows for equities, ETFs, and later crypto.

## Core workflow correction

Documents/import files are primarily for initial population and existing holdings. The long-term workflow must also support direct dashboard entry:

1. Search for instrument/coin.
2. Show multiple candidates when possible.
3. User selects the correct candidate.
4. User selects depot/account/wallet.
5. User enters quantity as Decimal/Text, date, snapshot/cost-basis info and note.
6. Save as an audited ledger transaction or initial snapshot.

Do not design the system so every future add depends on another document import.

## Identity rules

- Equity/ETF: ISIN is the primary identification, but one ISIN may have multiple listings.
- Ticker/symbol is not unique; it is only meaningful with exchange and currency.
- Provider symbol is only a market-data mapping, not the instrument truth.
- Name alone never justifies automatic mapping.
- Multiple candidates require manual selection and audit.
- Crypto: CoinGecko ID is the primary provider ID; crypto symbol alone is not unique.

## Privacy rules for provider/web lookups

Allowed external lookup fields:

- ISIN
- ticker/symbol
- public instrument name
- exchange
- currency
- public ETF/stock metadata

Never send externally:

- quantities
- depot/wallet/account identifiers
- balances or values
- cost basis / buy prices
- portfolio composition
- private notes
- real source documents/reports/extracts

Store lookup results locally in runtime DB/cache. Report only aggregate counts in chat.

## Local catalog shape

Implement/extend a local `instrument_catalog_entries` runtime table with fields such as:

- `catalog_entry_id`
- `asset_class` (`equity`, `etf`, `crypto`, `cash`, `other`)
- `name`, `normalized_name`
- `isin`, `ticker`, `exchange`
- `trading_currency`, `instrument_currency`
- `provider`, `provider_symbol`, `provider_market`
- `country`, `sector`, `issuer`, optional `fund_type`
- `is_currency_hedged`, `hedged_to_currency`, `hedge_status`
- `instrument_status`
- `valuation_policy`
- `source`, `source_confidence`
- `last_verified_at`, `notes`, timestamps

Allow multiple rows for the same ISIN with different exchange/currency/provider market.

## Search service pattern

Build `search_instruments(query, asset_class=None)` as:

1. Search local catalog first across ISIN, ticker/symbol, name, provider symbol, exchange and currency.
2. Query optional external providers only if configured.
3. Normalize all results into catalog-entry-shaped candidates.
4. Score confidence, but do not auto-finalize ambiguous matches.
5. If provider keys are missing or lookup fails, create/update `provider_lookup_unavailable` and continue.

Suggested provider modules:

- OpenFIGI for ISIN/FIGI/symbology mapping.
- Financial Modeling Prep for ISIN/symbol search.
- Finnhub for symbol lookup and later market data.
- Twelve Data for symbol/reference data and later prices.
- Yahoo only as fallback.

Do not hard-depend on a single provider.

## Dashboard UI pattern

Add/extend an Instrument Search / Add Position section:

- Search field and asset-class filters.
- Result list including symbol, name, ISIN, exchange, trading currency, provider, provider symbol, hedge status, instrument status and confidence.
- Candidate selection requires explicit confirmation.
- Manual catalog entry remains available when providers fail.
- Dashboard render must not call live APIs.

Manual Equity/ETF Add should write one audited ledger transaction/snapshot with:

- selected catalog entry
- account/depot
- `initial_snapshot`, `buy`, or `manual_adjustment`
- quantity as Decimal/Text, never float
- date
- currency
- optional cost basis
- FX status (`not_needed`, `missing`, `manual_override`, `manual_override_required`)
- note and confirm gate

## Data-quality outcomes

Create/dedupe alerts rather than inventing values:

- missing provider symbol → `missing_provider_symbol`
- multiple candidates → manual review / ambiguous mapping
- missing ISIN on equity/ETF → missing ISIN warning
- ticker without exchange → review needed, not automatic mapping
- hedge unknown → `hedge_status_unknown`
- instrument status unknown → `instrument_status_unknown`
- missing FX → `missing_fx` or `manual_override_required`
- missing market price → `missing_market_price`
- missing cost basis → `cost_basis_uncertain`
- unready valuation → suppress precise total return

## Runtime rollout pattern

For existing True Wealth / broker pilot positions:

1. Prepare catalog entries from the existing instruments.
2. Generate mapping-review packs/candidates if possible.
3. Do not final-select provider symbols automatically.
4. Do not fetch prices or set FX until mapping, hedge status, instrument status and valuation policy are confirmed.
5. Report only aggregate counts: instruments total, catalog entries, multiple listings, provider candidates, instruments without candidates, manual selection required, hedge unknown, instrument-status unknown, valuation-ready count.

## Minimum tests

- local search by ISIN
- local search by symbol
- same ISIN with multiple listings is shown
- symbol without exchange is not auto-mapped
- manual candidate selection writes audit log
- catalog stores multiple listings for same ISIN
- missing provider symbol produces DQ alert
- hedge unknown produces warning
- manual initial snapshot creates ledger transaction
- missing cost basis creates `cost_basis_uncertain`
- missing FX creates `missing_fx`
- dashboard render performs no live API call
- provider lookup failure does not crash
- Git-safety OK after test cache cleanup
