# True-Wealth Mapping Candidate Review (Phase C3)

Use this reference when hardening Equity/ETF market-data mappings after small True-Wealth initial-position imports.

## Scope and guardrails

- Do not import additional portfolio positions while mapping candidates are being reviewed.
- Do not expose real quantities, prices, balances, account values, raw rows, or source files in chat.
- Do not commit real files or runtime DB artifacts to Git.
- Dashboard/review pages must read local DB only; no live provider/API calls during render.
- Candidate creation is allowed in runtime DB; final provider-symbol selection remains manual unless the user explicitly approves and the match is unambiguous.
- No heatmaps, scores, rebalancing, backtesting, Monte-Carlo, or analytics pivots during this phase.

## Data model pattern

Create/extend a runtime table such as `instrument_price_mapping_candidates` with at least:

- `candidate_id` primary key
- `instrument_id`, `isin`
- `candidate_provider`, `candidate_provider_symbol`, `candidate_exchange`, `candidate_currency`, `candidate_name`
- `candidate_is_hedged`, `candidate_hedged_to_currency`
- `candidate_instrument_status`
- `confidence`: `high`, `medium`, `low`
- `evidence_source`, `evidence_note`
- `review_status`: `proposed`, `selected`, `rejected`, `needs_manual_review`
- `created_at`

Recommended uniqueness: `(instrument_id, candidate_provider, candidate_provider_symbol, candidate_exchange)` to keep candidate generation idempotent.

## Candidate generation rules

- ISIN match is strongest evidence and may be `high` confidence when provider symbol/currency/exchange are coherent.
- Name-only candidates are insufficient; mark `low` and `needs_manual_review`.
- Ticker without exchange remains review-required.
- Multiple candidates for the same instrument => all candidates `needs_manual_review` and create/keep a deduplicated `ambiguous_provider_mapping` alert.
- No candidate => keep/create deduplicated `missing_provider_symbol` alert.
- Provider lookup/API failure must not crash; create/keep `provider_lookup_unavailable` and continue.
- Hedge status may only be proposed automatically when obvious (`CHF hedged`, `hedged CHF`, `currency hedged`, etc.); the instrument itself remains `hedge_status=unknown` until user confirmation.
- Instrument status may be proposed `active` only with reliable provider evidence; otherwise keep `unknown`. Lookup failure is not enough to mark `delisted`.

## Review UI/service requirements

Instrument Price Mapping Review should allow:

- list instruments and mapping status
- show candidates and confidence/evidence
- select provider/provider-symbol/exchange/currency
- confirm hedge status: `hedged`, `unhedged`, `unknown`
- set hedged-to currency if hedged
- confirm instrument status: `active`, `suspended`, `delisted`, `merged`, `inactive`, `unknown`
- set valuation policy: `live_price`, `last_known_price`, `manual_value`, `exclude_from_auto_price_update`
- save selection with mandatory note/audit log
- resolve `missing_provider_symbol` and `ambiguous_provider_mapping` only after a confirmed selection

The selection service should write a normal provider mapping row separately from the candidate row and should never mutate positions/ledger rows.

## FX override review pattern

For foreign-currency snapshot positions:

- aggregate required FX pairs/dates only; do not print actual rates/values unless explicitly approved.
- keep `missing_fx`, `manual_override_required`, and/or `historical_fx_unavailable` active until a local historical rate or approved manual override exists.
- manual FX override requires pair, date, Decimal/Text rate, source/note, audit log, and resolves matching `missing_fx` alerts.
- do not set manual FX rates without explicit user approval.

## Testing checklist

Add tests for:

- ISIN-match candidate generation.
- Name-only candidate stays review-required.
- Multiple candidates become `needs_manual_review` and alert.
- No candidate keeps `missing_provider_symbol` active.
- Hedge unknown creates alert.
- CHF-hedged candidate remains `proposed` until confirmed.
- Instrument status unknown creates alert.
- Provider lookup failures do not crash.
- Mapping selection writes audit and resolves `missing_provider_symbol`.
- FX override requires note and resolves `missing_fx`.
- Market-price dry run without confirmed provider symbols calls no provider.
- Dashboard review UI renders without live API.
- Git-safety after tests, with generated caches removed.

## Runtime reporting shape

Report only aggregate counts:

- instruments total
- candidates found
- high/medium/low candidates
- instruments without candidate
- instruments with hedge unknown
- instruments with instrument-status unknown
- mapping actions performed: candidate creation only vs confirmed selections
- warnings/errors and active data-quality counts

Never report real quantities, prices, balances, account values, raw rows, or source filenames from real portfolio data.
