Output:
Chunk ID: eb4af3
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 4043
Output:
from __future__ import annotations

import base64
import json
from dataclasses import replace
from decimal import Decimal
from hashlib import sha256

import pytest

from jarvis_finance.dashboard.data import (
    get_cash_overview,
    get_command_center_summary,
    get_positions,
)
from jarvis_finance.imports.postfinance_documents import (
    PFBundle,
    PFDocument,
    PFEvent,
    PFSnapshot,
    PFSnapshotCash,
    PFSnapshotPosition,
    _reconcile_cash_components,
)
from jarvis_finance.services import postfinance_service as service
from jarvis_finance.services.cash_service import get_cash_position_detail, get_cash_summary
from jarvis_finance.services.equity_service import get_equity_summary
from jarvis_finance.services.portfolio_aggregation import (
    latest_official_postfinance_cash,
    latest_official_postfinance_positions,
)
from jarvis_finance.services.portfolio_analytics import confirmed_canonical_positions
from jarvis_finance.services.portfolio_data import build_portfolio_reconciliation
from jarvis_finance.services.portfolio_service import get_overview
from jarvis_finance.storage.database import connect_memory
from jarvis_finance.storage.migrations import apply_migrations

DEPOT = "account_pf_depot_test"
CASH = "account_pf_trading_cash_test"

def test_cash_component_reconciliation_preserves_negative_balances():
    reconciled = _reconcile_cash_components(
        [
            PFSnapshotCash("EUR", Decimal("-100"), Decimal("1"), Decimal("-100")),
            PFSnapshotCash("USD", Decimal("20"), Decimal("1"), Decimal("20")),
        ],
        Decimal("-80.01"),
    )
    assert [item.source_value_chf for item in reconciled] == [
        Decimal("-100.01"),
        Decimal("20.00"),
    ]
    assert sum((item.source_value_chf for item in reconciled), Decimal("0")) == Decimal(
        "-80.01"
    )

def make_conn():
    conn = connect_memory()
    apply_migrations(conn)
    conn.execute(
        "INSERT INTO platforms(platform_id,name,platform_type,country,default_currency,is_active,created_at) VALUES('pf','PostFinance','bank','CH','CHF',1,'2026-01-01')"
    )
    conn.execute(
        "INSERT INTO accounts(account_id,platform_id,account_name,account_type,currency,performance_included,is_active,created_at,portfolio_bucket) VALUES(?,'pf','PostFinance E-Trading','brokerage','CHF',1,1,'2026-01-01','postfinance')",
        (DEPOT,),
    )
    conn.execute(
        "INSERT INTO accounts(account_id,platform_id,account_name,account_type,currency,performance_included,is_active,created_at,portfolio_bucket) VALUES(?,'pf','PostFinance Cash-Konto','cash','CHF',1,1,'2026-01-01','cash')",
        (CASH,),
    )
    for index in range(22):
        instrument = f"instrument_pf_{index:02d}"
        label = f"Synthetic Asset {index + 1:02d}"
        conn.execute(
            "INSERT INTO instruments(instrument_id,name,ticker,isin,asset_class,currency,is_active,created_at) VALUES(?,?,?,?,?,?,1,?)",
            (
                instrument,
                label,
                f"S{index:02d}",
                f"CH{index:010d}",
                "equity" if index < 11 else "etf",
                "CHF",
                "2026-01-01",
            ),
        )
        conn.execute(
            "INSERT INTO positions_snapshot(position_snapshot_id,snapshot_date,account_id,platform_id,instrument_id,quantity,average_cost_original,cost_basis_original,market_price_original,market_value_original,market_fx_rate_to_chf,market_value_chf,category,data_quality_status,created_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
            (
                f"baseline_{index}",
                "2026-06-30",
                DEPOT,
                "pf",
                instrument,
                "1",
                "50",
                "50",
                "90",
                "90",
                "1",
                "90",
                "equity" if index < 11 else "etf",
                "complete",
                "2026-06-30T00:00:00Z",
            ),
        )
    conn.commit()
    return conn

def bundle(
    zip_raw: bytes = b"synthetic-zip", overview_raw: bytes = b"%PDF-synthetic-overview"
) -> PFBundle:
    zip_hash = sha256(zip_raw).hexdigest()
    overview_hash = sha256(overview_raw).hexdigest()
    doc_raw = b"%PDF-synthetic-trade"
    document = PFDocument(
        sha256(doc_raw).hexdigest(),
        sha256(b"trade.pdf").hexdigest(),
        "trade_confirmation",
        "synthetic-reference",
        sha256(b"semantic").hexdigest(),
        "2026-07-01",
        sha256(b"account").hexdigest(),
        "etrading_cash",
        1,
        doc_raw,
        "synthetic",
    )
    event = PFEvent(
        sha256(b"event").hexdigest(),
        document.document_hash,
        document.semantic_reference,
        "buy",
        "etrading_cash",
        "2026-07-01",
        "2026-07-03",
        "out",
        "Synthetic Asset 01",
        "CH0000000000",
        Decimal("1"),
        Decimal("50"),
        Decimal("50"),
        Decimal("1"),
        Decimal("0"),
        Decimal("51"),
        "CHF",
        Decimal("1"),
        None,
        "complete",
        (),
    )
    transfer_out = PFEvent(
        sha256(b"transfer-out").hexdigest(),
        document.document_hash,
        "transfer-reference",
        "internal_transfer",
        "efinance",
        "2026-07-02",
        "2026-07-02",
        "out",
        None,
        None,
        None,
        None,
        Decimal("10"),
        Decimal("0"),
        Decimal("0"),
        Decimal("10"),
        "CHF",
        Decimal("1"),
        "synthetic-transfer-group",
        "partial",
        ("internal_transfer_not_income_or_expense",),
    )
    transfer_in = PFEvent(
        sha256(b"transfer-in").hexdigest(),
        document.document_hash,
        "transfer-reference",
        "internal_transfer",
        "etrading_cash",
        "2026-07-02",
        "2026-07-02",
        "in",
        None,
        None,
        None,
        None,
        Decimal("10"),
        Decimal("0"),
        Decimal("0"),
        Decimal("10"),
        "CHF",
        Decimal("1"),
        "synthetic-transfer-group",
        "partial",
        ("internal_transfer_not_income_or_expense",),
    )
    positions = tuple(
        PFSnapshotPosition(
            sha256(f"row-{index}".encode()).hexdigest()[:32],
            f"Synthetic Asset {index + 1:02d}",
            f"synthetic asset {index + 1:02d}",
            "stock" if index < 11 else "etf",
            Decimal("1"),
            Decimal("50"),
            Decimal("50"),
            Decimal("100"),
            "CHF",
            Decimal("100"),
            Decimal("4.17"),
        )
        for index in range(22)
    )
    snapshot = PFSnapshot(
        overview_hash,
        5,
        "2026-07-27T09:14:30+02:00",
        positions,
        (
            PFSnapshotCash("EUR", Decimal("100"), Decimal("1"), Decimal("100")),
            PFSnapshotCash("USD", Decimal("100"), Decimal("1"), Decimal("100")),
        ),
        Decimal("2200"),
        Decimal("200"),
        Decimal("2400"),
        Decimal("1100"),
        Decimal("1100"),
        0,
    )
    return PFBundle(
        zip_hash,
        overview_hash,
        sha256((zip_hash + overview_hash).encode()).hexdigest(),
        (document,),
        (event, transfer_out, transfer_in),
        snapshot,
        ("synthetic-transfer-group",),
        (),
    )

def request(zip_raw: bytes = b"synthetic-zip", overview_raw: bytes = b"%PDF-synthetic-overview"):
    return {
        "zip_file_name": "documents.zip",
        "overview_file_name": "overview.pdf",
        "zip_content_base64": base64.b64encode(zip_raw).decode(),
        "overview_content_base64": base64.b64encode(overview_raw).decode(),
    }

def test_preview_confirm_and_reparse_are_atomic_idempotent_and_keep_roles_separate(
    monkeypatch, tmp_path
):
    conn = make_conn()
    calls = []
    monkeypatch.setenv("JARVIS_FINANCE_RUNTIME_DIR", str(tmp_path))
    monkeypatch.setattr(
        service,
        "parse_postfinance_bundle",
        lambda zip_raw, overview_raw: (
            calls.append((zip_raw, overview_raw)) or bundle(zip_raw, overview_raw)
        ),
    )
    payload = request()
    before = conn.total_changes
    preview = service.preview_postfinance_import(conn, payload)
    assert conn.total_changes == before
    assert preview["mapped_position_count"] == 22
    first = service.confirm_postfinance_import(
        conn,
        {
            **payload,
            "preview_id": preview["preview_id"],
            "confirmation_id": preview["confirmation_id"],
            "confirm": True,
        },
    )
    again_preview = service.preview_postfinance_import(conn, payload)
    second = service.confirm_postfinance_import(
        conn,
        {
            **payload,
            "preview_id": again_preview["preview_id"],
            "confirmation_id": again_preview["confirmation_id"],
            "confirm": True,
        },
    )
    assert len(calls) >= 4
    assert first["idempotent"] is False and second["idempotent"] is True
    safe_summary = service.get_postfinance_summary(conn)
    serialized = str(safe_summary)
    assert "account_pf_" not in serialized and "CH0000000000" not in serialized
    assert "snapshot_id" not in safe_summary["latest_snapshot"]
    assert "instrument_id" not in safe_summary["positions"][0]
    assert "batch_id" not in safe_summary["imports"][0]
    assert conn.execute("SELECT COUNT(*) FROM postfinance_import_batches").fetchone()[0] == 1
    assert conn.execute("SELECT COUNT(*) FROM postfinance_snapshots").fetchone()[0] == 1
    assert conn.execute("SELECT COUNT(*) FROM postfinance_snapshot_positions").fetchone()[0] == 22
    assert conn.execute("SELECT COUNT(*) FROM postfinance_account_roles").fetchone()[0] == 3
    roles = dict(conn.execute("SELECT role,account_id FROM postfinance_account_roles"))
    assert roles["etrading_depot"] == DEPOT
    assert roles["etrading_cash"] == CASH
    assert roles["efinance"] not in {DEPOT, CASH}
    assert len(set(roles.values())) == 3
    assert (
        conn.execute(
            "SELECT account_name FROM accounts WHERE account_id=?", (roles["efinance"],)
        ).fetchone()[0]
        == "PostFinance E-Finance"
    )
    transfer_rows = conn.execute(
        "SELECT account_id,activity_kind FROM transactions WHERE internal_transfer_group_id='synthetic-transfer-group' ORDER BY account_id"
    ).fetchall()
    assert {row["account_id"] for row in transfer_rows} == {roles["efinance"], CASH}
    assert {row["activity_kind"] for row in transfer_rows} == {"internal_transfer"}
    assert (
        conn.execute(
            "SELECT activity_kind FROM transactions WHERE source_type='postfinance_official_import'"
        ).fetchone()[0]
        == "trade"
    )
    assert len(list((tmp_path / "imports" / "postfinance" / "archive").glob("*"))) == 3

def test_provider_and_computed_cost_basis_are_separate(monkeypatch, tmp_path):
    conn = make_conn()
    monkeypatch.setenv("JARVIS_FINANCE_RUNTIME_DIR", str(tmp_path))
    monkeypatch.setattr(
        service,
        "parse_postfinance_bundle",
        lambda zip_raw, overview_raw: bundle(zip_raw, overview_raw),
    )
    payload = request()
    preview = service.preview_postfinance_import(conn, payload)
    service.confirm_postfinance_import(
        conn,
        {
            **payload,
            "preview_id": preview["preview_id"],
            "confirmation_id": preview["confirmation_id"],
            "confirm": True,
        },
    )
    first = conn.execute(
        "SELECT provider_cost_total_original,computed_cost_basis_original,computed_cost_basis_status FROM postfinance_snapshot_positions WHERE computed_cost_basis_original IS NOT NULL"
    ).fetchone()
    assert first[0] == "50" and first[1] == "51" and first[2] == "complete"
    assert conn.execute("SELECT COUNT(*) FROM postfinance_cost_basis_lots").fetchone()[0] == 1

def test_sell_consumes_documented_fifo_lot_before_cost_basis_persistence(monkeypatch, tmp_path):
    conn = make_conn()
    monkeypatch.setenv("JARVIS_FINANCE_RUNTIME_DIR", str(tmp_path))
    original = bundle()
    buy = replace(
        original.events[0],
        quantity=Decimal("2"),
        gross_original=Decimal("100"),
        net_original=Decimal("101"),
    )
    sell = replace(
        buy,
        event_fingerprint=sha256(b"sell-event").hexdigest(),
        event_type="sell",
        occurred_on="2026-07-10",
        direction="in",
        quantity=Decimal("1"),
        price_original=Decimal("60"),
        gross_original=Decimal("60"),
        fee_original=Decimal("1"),
        net_original=Decimal("59"),
    )
    fifo_bundle = replace(original, events=(buy, sell, *original.events[1:]))
    monkeypatch.setattr(service, "parse_postfinance_bundle", lambda _zip, _overview: fifo_bundle)
    payload = request()
    preview = service.preview_postfinance_import(conn, payload)
    service.confirm_postfinance_import(
        conn,
        {
            **payload,
            "preview_id": preview["preview_id"],
            "confirmation_id": preview["confirmation_id"],
            "confirm": True,
        },
    )
    lot = conn.execute(
        "SELECT quantity_acquired,quantity_remaining FROM postfinance_cost_basis_lots"
    ).fetchone()
    assert tuple(lot) == ("2", "1")
    computed = conn.execute(
        "SELECT computed_cost_basis_original,computed_cost_basis_status FROM postfinance_snapshot_positions WHERE computed_cost_basis_original IS NOT NULL"
    ).fetchone()
    assert tuple(computed) == ("50.5", "complete")

def test_same_snapshot_with_different_original_source_is_blocked(monkeypatch, tmp_path):
    conn = make_conn()
    monkeypatch.setenv("JARVIS_FINANCE_RUNTIME_DIR", str(tmp_path))
    monkeypatch.setattr(
        service,
        "parse_postfinance_bundle",
        lambda zip_raw, overview_raw: bundle(zip_raw, overview_raw),
    )
    payload = request()
    preview = service.preview_postfinance_import(conn, payload)
    service.confirm_postfinance_import(
        conn,
        {
            **payload,
            "preview_id": preview["preview_id"],
            "confirmation_id": preview["confirmation_id"],
            "confirm": True,
        },
    )
    alternate = request(b"synthetic-zip-revision", b"%PDF-synthetic-overview-revision")
    conflict = service.preview_postfinance_import(conn, alternate)
    assert conflict["conflict"] is True
    with pytest.raises(ValueError, match="conflict"):
        service.confirm_postfinance_import(
            conn,
            {
                **alternate,
                "preview_id": conflict["preview_id"],
                "confirmation_id": conflict["confirmation_id"],
                "confirm": True,
            },
        )
    assert conn.execute("SELECT COUNT(*) FROM postfinance_import_batches").fetchone()[0] == 1

def test_existing_same_day_canonical_projection_is_blocked_during_preview(monkeypatch):
    conn = make_conn()
    conn.execute(
        """INSERT INTO positions_snapshot(position_snapshot_id,snapshot_date,account_id,platform_id,
               instrument_id,quantity,market_value_chf,data_quality_status,created_at)
           VALUES('same-day','2026-07-27',?,'pf','instrument_pf_00','1','100','complete','2026-07-27')""",
        (DEPOT,),
    )
    conn.commit()
    monkeypatch.setattr(service, "parse_postfinance_bundle", lambda _zip, _overview: bundle())
    preview = service.preview_postfinance_import(conn, request())
    assert preview["conflict"] is True
    assert preview["conflicting_batch_id"] == "canonical_projection_date_conflict"

def test_immutable_postfinance_source_and_snapshot_rows(monkeypatch, tmp_path):
    conn = make_conn()
    monkeypatch.setenv("JARVIS_FINANCE_RUNTIME_DIR", str(tmp_path))
    monkeypatch.setattr(
        service,
        "parse_postfinance_bundle",
        lambda zip_raw, overview_raw: bundle(zip_raw, overview_raw),
    )
    payload = request()
    preview = service.preview_postfinance_import(conn, payload)
    result = service.confirm_postfinance_import(
        conn,
        {


sed -n '460,920p' tests/test_postfinance_sprint13.py


Output:
Chunk ID: bbbf58
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 5275
Output:
        {
            **payload,
            "preview_id": preview["preview_id"],
            "confirmation_id": preview["confirmation_id"],
            "confirm": True,
        },
    )
    with pytest.raises(Exception, match="immutable"):
        conn.execute(
            "UPDATE postfinance_snapshots SET total_chf='0' WHERE snapshot_id=?",
            (result["snapshot_id"],),
        )
    with pytest.raises(Exception, match="cannot be deleted"):
        conn.execute(
            "DELETE FROM postfinance_snapshots WHERE snapshot_id=?", (result["snapshot_id"],)
        )
    immutable_columns = {
        "postfinance_batch_documents": "document_hash=document_hash",
        "postfinance_snapshot_positions": "created_at=created_at",
        "postfinance_snapshot_cash": "created_at=created_at",
        "postfinance_event_components": "created_at=created_at",
    }
    for table, assignment in immutable_columns.items():
        with pytest.raises(Exception, match="immutable"):
            conn.execute(f"UPDATE {table} SET {assignment}")
        with pytest.raises(Exception, match="cannot be deleted"):
            conn.execute(f"DELETE FROM {table}")
    canonical_tables = {
        "positions_snapshot": "source_type='postfinance_official_import'",
        "cash_balances": "source_type='postfinance_official_import'",
        "transactions": "source_type='postfinance_official_import'",
    }
    for table, predicate in canonical_tables.items():
        with pytest.raises(Exception, match="immutable"):
            conn.execute(f"UPDATE {table} SET created_at=created_at WHERE {predicate}")
        with pytest.raises(Exception, match="cannot be deleted"):
            conn.execute(f"DELETE FROM {table} WHERE {predicate}")

def test_global_read_model_counts_official_postfinance_components_once(monkeypatch, tmp_path):
    """Reproduce the production placeholder/exposure/settlement-position collision."""
    conn = make_conn()
    monkeypatch.setenv("JARVIS_FINANCE_RUNTIME_DIR", str(tmp_path))
    original = bundle()
    stock_total = Decimal("255791.97")
    etf_total = Decimal("37673.19")

    def split_total(total: Decimal) -> list[Decimal]:
        values = [(total / Decimal("11")).quantize(Decimal("0.01")) for _ in range(11)]
        values[-1] += total - sum(values, Decimal("0"))
        return values

    source_values = split_total(stock_total) + split_total(etf_total)
    positions = tuple(
        replace(item, quantity=Decimal("1"), market_price_original=value, market_value_chf=value)
        for item, value in zip(original.snapshot.positions, source_values, strict=True)
    )
    realistic = replace(
        original,
        snapshot=replace(
            original.snapshot,
            positions=positions,
            cash=(
                PFSnapshotCash("EUR", Decimal("21693.27"), Decimal("0.9293"), Decimal("71623.09")),
                PFSnapshotCash("USD", Decimal("9235.55"), Decimal("0.8146"), Decimal("249526.14")),
            ),
            securities_total_chf=Decimal("293465.16"),
            cash_total_chf=Decimal("27684.07"),
            total_value_chf=Decimal("321149.23"),
            stock_total_chf=stock_total,
            etf_total_chf=etf_total,
        ),
    )
    monkeypatch.setattr(service, "parse_postfinance_bundle", lambda _zip, _overview: realistic)
    conn.execute(
        """INSERT INTO cash_account_snapshots(snapshot_id,account_id,snapshot_type,balance_date,
               amount_original,currency,amount_chf,source,note,created_at,created_by)
           VALUES('legacy-total',?,'manual_balance','2026-07-26','321149.23','CHF',
                  '321149.23','manual','historical depot total placeholder',
                  '2026-07-26T00:00:00Z','synthetic')""",
        (CASH,),
    )
    conn.execute(
        "INSERT INTO platforms(platform_id,name,platform_type,country,default_currency,is_active,created_at) VALUES('tw','True Wealth','wealth','CH','CHF',1,'2026-01-01')"
    )
    conn.execute(
        """INSERT INTO accounts(account_id,platform_id,account_name,account_type,currency,
               performance_included,is_active,created_at,portfolio_bucket)
           VALUES('account_tw','tw','True Wealth','brokerage','CHF',1,1,'2026-01-01','truewealth')"""
    )
    conn.execute(
        """INSERT INTO account_value_snapshots(snapshot_id,account_id,valuation_date,
               total_value_chf,currency,source_type,quality_status,created_at,is_active)
           VALUES('tw-value','account_tw','2026-07-27','152845.00','CHF',
                  'synthetic_truewealth','complete','2026-07-27T00:00:00Z',1)"""
    )
    conn.commit()

    payload = request()
    preview = service.preview_postfinance_import(conn, payload)
    service.confirm_postfinance_import(
        conn,
        {**payload, "preview_id": preview["preview_id"],
         "confirmation_id": preview["confirmation_id"], "confirm": True},
    )
    before_gets = conn.total_changes
    cash = get_cash_summary(conn)
    equity = get_equity_summary(conn)
    overview = get_overview(conn)
    command = get_command_center_summary(conn)
    reconciliation = build_portfolio_reconciliation(conn, as_of="2026-07-27")
    rows = get_positions(conn)

    assert conn.total_changes == before_gets
    assert cash.cash_chf == "27684.07"
    assert sum(Decimal(item.used_value_chf) for item in cash.positions if item.account_id == CASH) == Decimal("27684.07")
    usd_position = next(item for item in cash.positions if item.account_id == CASH and item.currency == "USD")
    assert get_cash_position_detail(conn, usd_position.id).currency == "USD"
    assert equity.equity_value_chf == "293465.16"
    assert equity.as_of == "2026-07-27T09:14:30+02:00"
    assert sum(Decimal(row["market_value_chf"]) for row in rows if row["account_id"] == DEPOT) == Decimal("293465.16")
    assert not [row for row in rows if row["account_id"] == CASH and row["asset_class"] in {"stock", "equity", "etf"}]
    assert Decimal(cash.cash_chf) + Decimal(equity.equity_value_chf) == Decimal("321149.23")
    assert overview.truewealth_value_chf == "152845.00"
    assert command["cash_total_chf"] == "27684.07"
    pf_reconciliation = next(
        item for item in reconciliation["account_totals"]
        if item["reported_total"] == "321149.23"
    )
    assert pf_reconciliation["derived_total"] == "321149.23"
    assert pf_reconciliation["status"] == "matched"
    assert conn.execute("SELECT amount_chf FROM cash_account_snapshots WHERE snapshot_id='legacy-total'").fetchone()[0] == "321149.23"
    assert conn.execute("SELECT COUNT(*) FROM transactions WHERE internal_transfer_group_id IS NOT NULL").fetchone()[0] == 2

    market_positions = []
    for row, value in zip(
        [row for row in rows if row["account_id"] == DEPOT],
        split_total(Decimal("160000")) + split_total(Decimal("140000")),
        strict=True,
    ):
        market_positions.append({
            "account_id": DEPOT, "instrument_id": row["instrument_id"],
            "quality_status": "fresh", "value_chf": str(value), "close": str(value),
            "currency": "CHF", "provider": "synthetic-market",
        })
    conn.execute(
        """INSERT INTO market_data_runs(run_id,source_key,as_of,input_fingerprint,status,
               started_at,completed_at,price_total,price_stored,fx_total,fx_stored,
               benchmark_total,benchmark_stored,valuation_stored,missing_instruments_json,
               reason_codes_json)
           VALUES('newer-run','synthetic','2026-07-28','fp','complete','2026-07-28T00:00:00Z',
                  '2026-07-28T00:01:00Z',22,22,0,0,0,0,22,'[]','[]')"""
    )
    conn.execute(
        """INSERT INTO portfolio_analysis_snapshots(analysis_snapshot_id,run_id,as_of,
               base_currency,total_value_chf,price_coverage_pct,fx_coverage_pct,
               benchmark_coverage_pct,quality_status,reason_codes_json,summary_json,created_at)
           VALUES('newer-analysis','newer-run','2026-07-28','CHF','300000','100','100','0',
                  'complete','[]',?,'2026-07-28T00:01:00Z')""",
        (json.dumps({"positions": market_positions}),),
    )
    conn.commit()
    newer = get_equity_summary(conn)
    assert newer.equity_value_chf == "300000.00"
    assert newer.as_of == "2026-07-28"
    assert get_cash_summary(conn).cash_chf == "27684.07"
    assert service.get_postfinance_summary(conn)["latest_snapshot"]["total_chf"] == "321149.23"

    duplicate = service.preview_postfinance_import(conn, payload)
    second = service.confirm_postfinance_import(
        conn,
        {**payload, "preview_id": duplicate["preview_id"],
         "confirmation_id": duplicate["confirmation_id"], "confirm": True},
    )
    assert duplicate["duplicate"] is True and duplicate["conflict"] is False
    assert second["idempotent"] is True
    assert conn.execute("SELECT COUNT(*) FROM postfinance_import_batches").fetchone()[0] == 1

def test_official_snapshot_resolvers_honor_historical_as_of_and_cutoff(monkeypatch, tmp_path):
    conn = make_conn()
    monkeypatch.setenv("JARVIS_FINANCE_RUNTIME_DIR", str(tmp_path))
    monkeypatch.setattr(service, "parse_postfinance_bundle", lambda _zip, _overview: bundle())
    payload = request()
    preview = service.preview_postfinance_import(conn, payload)
    service.confirm_postfinance_import(
        conn,
        {**payload, "preview_id": preview["preview_id"],
         "confirmation_id": preview["confirmation_id"], "confirm": True},
    )
    original_cash_total = sum(
        (item.amount_chf for item in latest_official_postfinance_cash(conn)), Decimal("0")
    )
    original_position_total = sum(
        (
            item.market_value_chf
            for item in latest_official_postfinance_positions(conn).values()
        ),
        Decimal("0"),
    )
    conn.execute("UPDATE accounts SET account_type='checking' WHERE account_id=?", (CASH,))
    assert sum(
        (
            Decimal(item.used_value_chf)
            for item in get_cash_summary(conn).positions
            if item.account_id == CASH
        ),
        Decimal("0"),
    ) == original_cash_total
    platform_id = conn.execute(
        "SELECT platform_id FROM accounts WHERE account_id=?", (CASH,)
    ).fetchone()["platform_id"]
    conn.execute(
        """INSERT INTO accounts(
               account_id,platform_id,account_name,account_type,currency,balance_mode,
               portfolio_bucket,is_active,created_at)
           VALUES('generic-usd-cash',?,'Generic Multi-Currency','cash','CHF','csv_calculated',
                  'cash',1,'2026-07-27T10:00:00Z')""",
        (platform_id,),
    )
    conn.execute(
        """INSERT INTO transactions(
               transaction_id,transaction_type,account_id,trade_date,gross_amount_original,
               net_amount_original,currency_original,fx_rate_to_chf,fx_status,source_type,
               source_id,is_confirmed,quality_status,created_at)
           VALUES('generic-usd-deposit','cash_deposit','generic-usd-cash','2026-07-27',
                  '100','100','USD','0.9','ok','csv_import','generic-usd-deposit',1,
                  'ok','2026-07-27T10:00:00Z')"""
    )
    conn.execute(
        """INSERT INTO transactions(
               transaction_id,transaction_type,account_id,trade_date,gross_amount_original,
               net_amount_original,currency_original,fx_rate_to_chf,fx_status,source_type,
               source_id,is_confirmed,quality_status,created_at)
           VALUES('generic-eur-deposit','cash_deposit','generic-usd-cash','2026-07-27',
                  '50','50','EUR','1.1','ok','csv_import','generic-eur-deposit',1,
                  'ok','2026-07-27T10:00:01Z')"""
    )
    conn.execute(
        """INSERT INTO cash_balances(
               cash_balance_id,account_id,balance_date,currency,amount_original,
               fx_rate_to_chf,amount_chf,source_type,quality_status,created_at)
           VALUES('generic-gbp-dividend','generic-usd-cash','2026-07-27','GBP','10',
                  '1.1','11','vue_equity_dividend','ok','2026-07-27T10:00:02Z')"""
    )
    generic_rows = [
        row for row in get_cash_overview(conn) if row["account_id"] == "generic-usd-cash"
    ]
    assert {row["currency"] for row in generic_rows} == {"EUR", "GBP", "USD"}
    generic_usd = next(row for row in generic_rows if row["currency"] == "USD")
    generic_eur = next(row for row in generic_rows if row["currency"] == "EUR")
    generic_gbp = next(row for row in generic_rows if row["currency"] == "GBP")
    assert generic_usd["amount_original"] == "100.00"
    assert generic_usd["amount_chf"] == "90.00"
    assert generic_eur["amount_original"] == "50.00"
    assert generic_eur["amount_chf"] == "55.00"
    assert generic_gbp["amount_original"] == "10.00"
    assert generic_gbp["amount_chf"] == "11.00"
    conn.execute(
        "UPDATE accounts SET balance_mode='manual' WHERE account_id='generic-usd-cash'"
    )
    conn.execute(
        """INSERT INTO cash_account_snapshots(
               snapshot_id,account_id,snapshot_type,balance_date,amount_original,currency,
               amount_chf,source,created_at,created_by)
           VALUES('generic-manual-total','generic-usd-cash','manual_balance','2026-07-27',
                  '1000','CHF','1000','manual','2026-07-27T10:01:00Z','user')"""
    )
    conn.execute(
        """INSERT INTO cash_balances(
               cash_balance_id,account_id,balance_date,currency,amount_original,
               fx_rate_to_chf,amount_chf,source_type,quality_status,created_at)
           VALUES('generic-missing-fx','generic-usd-cash','2026-07-27','GBP','10',
                  NULL,NULL,'manual_import','missing_fx','2026-07-27T10:01:01Z')"""
    )
    controlled_rows = [
        row for row in get_cash_overview(conn) if row["account_id"] == "generic-usd-cash"
    ]
    assert [(row["currency"], row["amount_chf"]) for row in controlled_rows] == [
        ("CHF", "1000.00")
    ]

    batch = dict(conn.execute("SELECT * FROM postfinance_import_batches LIMIT 1").fetchone())
    batch.update(
        batch_id="future-batch",
        bundle_sha256=sha256(b"future-bundle").hexdigest(),
        snapshot_at="2026-08-01T09:14:30+02:00",
        confirmed_at="2026-08-01T10:00:00Z",
    )
    columns = list(batch)
    conn.execute(
        f"INSERT INTO postfinance_import_batches({','.join(columns)}) VALUES({','.join('?' for _ in columns)})",
        [batch[column] for column in columns],
    )
    source_snapshot = dict(conn.execute("SELECT * FROM postfinance_snapshots LIMIT 1").fetchone())
    source_snapshot.update(
        snapshot_id="future-snapshot",
        batch_id="future-batch",
        snapshot_at="2026-08-01T09:14:30+02:00",
        total_chf="1299.00",
        securities_chf="300.00",
        cash_chf="999.00",
        stocks_chf="100.00",
        etfs_chf="200.00",
        component_total_chf="1299.00",
        difference_chf="0.00",
        created_at="2026-08-01T10:00:00Z",
    )
    columns = list(source_snapshot)
    conn.execute(
        f"INSERT INTO postfinance_snapshots({','.join(columns)}) VALUES({','.join('?' for _ in columns)})",
        [source_snapshot[column] for column in columns],
    )
    conn.execute(
        """INSERT INTO postfinance_snapshot_positions(
               snapshot_position_id,snapshot_id,source_row_reference,instrument_id,asset_class,
               quantity,provider_average_cost_original,provider_cost_total_original,
               price_original,price_currency,value_chf,weight_pct,computed_cost_basis_original,
               computed_cost_basis_status,provenance_json,created_at)
           SELECT 'future-'||snapshot_position_id,'future-snapshot',source_row_reference,
                  instrument_id,asset_class,quantity,provider_average_cost_original,
                  provider_cost_total_original,price_original,price_currency,value_chf,weight_pct,
                  computed_cost_basis_original,computed_cost_basis_status,provenance_json,
                  '2026-08-01T10:00:00Z'
           FROM postfinance_snapshot_positions WHERE snapshot_id<> 'future-snapshot'"""
    )
    conn.execute(
        """INSERT INTO postfinance_snapshot_cash(
               snapshot_cash_id,snapshot_id,currency,amount_original,fx_rate_to_chf,value_chf,created_at)
           SELECT 'future-'||snapshot_cash_id,'future-snapshot',currency,amount_original,
                  fx_rate_to_chf,value_chf,'2026-08-01T10:00:00Z'
           FROM postfinance_snapshot_cash WHERE snapshot_id<> 'future-snapshot'"""
    )
    conn.commit()

    assert sum((item.amount_chf for item in latest_official_postfinance_cash(conn)), Decimal("0")) == Decimal("999.00")
    historical_cash = latest_official_postfinance_cash(conn, as_of="2026-07-27")
    assert sum((item.amount_chf for item in historical_cash), Decimal("0")) == original_cash_total
    cutoff_cash = latest_official_postfinance_cash(
        conn,
        as_of="2026-08-01",
        data_cutoff="2026-07-31T23:59:59Z",
    )
    assert sum((item.amount_chf for item in cutoff_cash), Decimal("0")) == original_cash_total
    historical_positions = latest_official_postfinance_positions(conn, as_of="2026-07-27")
    assert sum(
        (item.market_value_chf for item in historical_positions.values()), Decimal("0")
    ) == original_position_total
    assert {item.valuation_at for item in historical_positions.values()} == {"2026-07-27T09:14:30+02:00"}
    current_positions = latest_official_postfinance_positions(conn)
    assert sum((item.market_value_chf for item in current_positions.values()), Decimal("0")) == Decimal("300.00")
    assert {item.valuation_at for item in current_positions.values()} == {"2026-08-01T09:14:30+02:00"}

    selected = next(iter(current_positions.values()))
    baseline_quantity = selected.quantity
    conn.execute(
        """INSERT INTO transactions(
               transaction_id,transaction_type,account_id,instrument_id,trade_date,
               settlement_date,quantity,currency_original,source_type,source_id,
               external_transaction_id,row_hash,is_confirmed,quality_status,created_at,
               updated_at,is_voided)
           VALUES('post-snapshot-buy','buy',?,?, '2026-08-02','2026-08-02','2',
                  'CHF','manual_confirmed_trade','post-snapshot-buy','post-snapshot-buy',?,
                  1,'ok','2026-08-02T10:00:00Z','2026-08-02T10:00:00Z',0)""",
        (CASH, selected.instrument_id, sha256(b"post-snapshot-buy").hexdigest()),
    )
    conn.execute(
        """INSERT INTO transactions(
               transaction_id,transaction_type,account_id,trade_date,gross_amount_original,
               net_amount_original,currency_original,fx_rate_to_chf,fx_status,source_type,
               source_id,is_confirmed,quality_status,created_at,is_voided)
           VALUES('post-snapshot-cash','cash_deposit',?,'2026-08-02','10','10','USD',
                  '0.8','ok','manual_confirmed_cash','post-snapshot-cash',1,'ok',
                  '2026-08-02T10:01:00Z',0)""",
        (CASH,),
    )
    conn.execute(
        """INSERT INTO transactions(
               transaction_id,transaction_type,account_id,instrument_id,trade_date,
               settlement_date,quantity,gross_amount_original,net_amount_original,
               currency_original,fx_rate_to_chf,fx_status,source_type,source_id,
               is_confirmed,quality_status,created_at,is_voided)
           VALUES('post-snapshot-sell','sell',?,?, '2026-08-02','2026-08-02','1',
                  '20','20','USD','0.8','ok','manual_confirmed_trade',
                  'post-snapshot-sell',1,'ok','2026-08-02T10:02:00Z',0)""",
        (CASH, selected.instrument_id),
    )
    conn.execute(
        """INSERT INTO cash_balances(
               cash_balance_id,account_id,balance_date,currency,amount_original,
               fx_rate_to_chf,amount_chf,source_type,quality_status,created_at)
           VALUES('post-snapshot-dividend-cash',?,'2026-08-02','EUR','5','1','5',
                  'vue_equity_dividend','ok','2026-08-02T10:03:00Z')""",
        (CASH,),
    )
    conn.commit()
    post_snapshot_cash = [
        item for item in get_cash_summary(conn).positions if item.account_id == CASH
    ]
    assert sum(
        (Decimal(item.used_value_chf) for item in post_snapshot_cash), Decimal("0")
    ) == Decimal("1028.00")
    assert next(item for item in post_snapshot_cash if item.currency == "USD").amount == "130.00"
    assert next(item for item in post_snapshot_cash if item.currency == "EUR").amount == "105.00"
    dashboard_position = next(
        row
        for row in get_positions(conn)
        if row["account_id"] == DEPOT and row["instrument_id"] == selected.instrument_id
    )
    assert Decimal(dashboard_position["quantity"]) == baseline_quantity + Decimal("1")
    canonical_position = next(
        item
        for item in confirmed_canonical_positions(conn, as_of="2026-08-02")
        if item.account_id == DEPOT and item.instrument_id == selected.instrument_id
    )
    assert canonical_position.quantity == baseline_quantity + Decimal("1")


sed -n '500,620p' src/jarvis_finance/services/cash_service.py && grep -R "get_cash_position_detail" -n src tests | head -20


Output:
Chunk ID: 5bc38a
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1140
Output:

def confirm_cash_snapshot(conn: Connection, request: CashSnapshotConfirmRequest) -> ConfirmResponse:
    if not request.confirm:
        raise HTTPException(status_code=400, detail="Explicit confirm required")
    preview_cash_snapshot(conn, request)
    amount = _decimal(request.amount_chf, "amount_chf")
    snapshot_id = _uuid("cashsnap")
    now = _now()
    source = "manual" if request.snapshot_type in {"manual_balance", "reconciliation"} else "csv_import" if request.snapshot_type == "csv_anchor_balance" else "system_calculated"
    audit_id = _audit(conn, action=f"cash_{request.snapshot_type}_confirm", entity_type="cash_account", entity_id=request.account_id, payload=request.model_dump(), note=request.note)
    conn.execute(
        """
        INSERT INTO cash_account_snapshots(snapshot_id, account_id, snapshot_type, balance_date, amount_original, currency, amount_chf, source, note, created_at, created_by, audit_id)
        VALUES (?, ?, ?, ?, ?, 'CHF', ?, ?, ?, ?, 'user', ?)
        """,
        (snapshot_id, request.account_id, request.snapshot_type, request.balance_date, decimal_text(amount, 2), decimal_text(amount, 2), source, request.note, now, audit_id),
    )
    conn.commit()
    return ConfirmResponse(status="confirmed", entity_id=snapshot_id, audit_id=audit_id, message="Kontostand gespeichert · Audit geschrieben")

def get_cash_position_detail(conn: Connection, position_id: str) -> CashPositionDetail:
    position = next((p for p in get_cash_summary(conn).positions if p.id == position_id), None)
    if not position:
        raise HTTPException(status_code=404, detail="Cash position not found")
    account_id = position.account_id
    rows = conn.execute(
        """
        SELECT snapshot_id, snapshot_type, balance_date, amount_chf, source, COALESCE(note,'') AS note, audit_id
        FROM cash_account_snapshots
        WHERE account_id=?
        ORDER BY balance_date DESC, created_at DESC
        LIMIT 30
        """,
        (account_id,),
    ).fetchall()
    history: list[CashSnapshot] = []
    previous: Decimal | None = None
    for row in reversed(rows):
        current = Decimal(str(row["amount_chf"]))
        diff = None if previous is None else decimal_text(current - previous, 2)
        previous = current
        history.append(CashSnapshot(snapshot_id=row["snapshot_id"], snapshot_type=row["snapshot_type"], balance_date=row["balance_date"], amount_chf=decimal_text(current, 2), source=row["source"], note=row["note"], difference_to_previous_chf=diff, audit_hint="Audit vorhanden" if row["audit_id"] else None))
    history = list(reversed(history))
    return CashPositionDetail(**position.model_dump(), last_change=position.last_manual_reconciliation, history=history, available_actions=[ActionItem(label="Einzahlung", enabled=True), ActionItem(label="Auszahlung", enabled=True), ActionItem(label="Kontostand aktualisieren", enabled=True), ActionItem(label="CSV-Anfangsstand setzen", enabled=True), ActionItem(label="Abgleich bestätigen", enabled=True), ActionItem(label="Verlauf anzeigen", enabled=True)])
grep: src/jarvis_finance/api/routers/__pycache__/cash.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/cash_service.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/manual_entry_service.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/cash_service.cpython-312.pyc: binary file matches
grep: tests/__pycache__/test_postfinance_sprint13.cpython-311-pytest-9.1.1.pyc: binary file matches
grep: tests/__pycache__/test_postfinance_sprint13.cpython-311.pyc: binary file matches
grep: tests/__pycache__/test_postfinance_sprint13.cpython-311-pytest-9.0.2.pyc: binary file matches
src/jarvis_finance/api/routers/cash.py:10:from jarvis_finance.services.cash_service import confirm_cash_snapshot, get_cash_position_detail, get_cash_summary, preview_cash_snapshot
src/jarvis_finance/api/routers/cash.py:23:    return get_cash_position_detail(conn, position_id)
src/jarvis_finance/services/manual_entry_service.py:571:def get_cash_position_detail(conn: Connection, position_id: str) -> CashPositionDetail:
src/jarvis_finance/services/cash_service.py:521:def get_cash_position_detail(conn: Connection, position_id: str) -> CashPositionDetail:
tests/test_postfinance_sprint13.py:26:from jarvis_finance.services.cash_service import get_cash_position_detail, get_cash_summary
tests/test_postfinance_sprint13.py:577:    assert get_cash_position_detail(conn, usd_position.id).currency == "USD"


grep -R "class CashPosition" -n src/jarvis_finance/api/schemas src/jarvis_finance | head -20 && sed -n '1,140p' src/jarvis_finance/api/schemas/positions.py


Output:
Chunk ID: b63141
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 940
Output:
src/jarvis_finance/api/schemas/positions.py:148:class CashPosition(BaseModel):
src/jarvis_finance/api/schemas/positions.py:168:class CashPositionDetail(CashPosition):
src/jarvis_finance/api/schemas/positions.py:148:class CashPosition(BaseModel):
src/jarvis_finance/api/schemas/positions.py:168:class CashPositionDetail(CashPosition):
from __future__ import annotations

from pydantic import BaseModel

class ActionItem(BaseModel):
    label: str
    enabled: bool
    reason: str | None = None

class PricePoint(BaseModel):
    date: str
    value: str
    currency: str = "CHF"
    provider: str | None = None
    quality_status: str | None = None

class CryptoPosition(BaseModel):
    asset_id: str
    name: str
    symbol: str
    quantity_total: str
    price_chf: str | None = None
    market_value_chf: str | None = None
    portfolio_share_pct: str
    wallet_count: int
    price_status: str
    last_price_update: str | None = None
    coingecko_url: str | None = None

class WalletAllocation(BaseModel):
    wallet_id: str
    wallet: str
    quantity: str
    market_value_chf: str | None = None

class WalletCoin(BaseModel):
    asset_id: str
    name: str
    symbol: str
    quantity: str
    market_value_chf: str | None = None
    status: str

class CoinGeckoInfo(BaseModel):
    market_cap_rank: int | None = None
    market_cap: str | None = None
    volume_24h: str | None = None
    change_24h_pct: str | None = None
    change_7d_pct: str | None = None
    homepage: str | None = None
    image_url: str | None = None

class CryptoPositionDetail(CryptoPosition):
    wallet_allocations: list[WalletAllocation]
    coingecko_info: CoinGeckoInfo | None = None
    available_actions: list[ActionItem] = []
    price_history: list[PricePoint] = []
    read_only_note: str = "Live-Modus später; keine Provider-Abfrage beim Rendern."

class WalletSummary(BaseModel):
    wallet_id: str
    name: str
    wallet_type: str
    provider: str = ""
    coin_count: int
    market_value_chf: str | None = None
    status: str

class WalletDetail(WalletSummary):
    coins: list[WalletCoin]

class EquityPosition(BaseModel):
    position_id: str
    instrument_id: str | None = None
    name: str
    ticker: str = ""
    isin: str = ""
    account: str = ""
    asset_class: str
    quantity: str
    currency: str
    price: str | None = None
    market_value_chf: str | None = None
    portfolio_share_pct: str | None = None
    price_date: str | None = None
    provider: str | None = None
    provider_symbol: str | None = None
    exchange: str | None = None
    price_currency: str | None = None
    data_status: str = "missing"
    status_code: str = "price_missing"
    status_reason: str | None = None
    status: str

class EquityPortfolioSummary(BaseModel):
    total_positions: int
    valued_positions: int
    unvalued_positions: int
    coverage_complete: bool
    equity_value_chf: str | None = None
    valued_partial_chf: str
    value_label: str
    as_of: str | None = None
    last_successful_run: str | None = None
    status: str
    status_label: str
    unvalued_tickers: list[str] = []

class EquityPositionDetail(EquityPosition):
    fx_status: str = "not_needed"
    cost_basis_status: str = "unknown"
    day_change_chf: str | None = None
    last_trade_date: str | None = None
    provider: str | None = None
    source_url: str | None = None
    provider_symbol: str | None = None
    exchange: str | None = None
    price_currency: str | None = None
    fx_rate_to_chf: str | None = None
    data_source: str | None = None
    available_actions: list[ActionItem]
    price_history: list[PricePoint] = []

class CashSnapshot(BaseModel):
    snapshot_id: str
    snapshot_type: str
    balance_date: str


sed -n '140,220p' src/jarvis_finance/api/schemas/positions.py && grep -R "class CashCalculation" -n src/jarvis_finance/ledger/cash.py


Output:
Chunk ID: ede39d
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 507
Output:
    balance_date: str
    amount_chf: str
    source: str
    note: str = ""
    difference_to_previous_chf: str | None = None
    audit_hint: str | None = None

class CashPosition(BaseModel):
    id: str
    account_id: str = ""
    platform: str
    account_label: str
    account_type: str = "cash"
    currency: str
    balance_mode: str = "manual"
    amount: str
    amount_chf: str | None = None
    calculated_balance_chf: str = "0.00"
    manual_balance_chf: str | None = None
    csv_anchor_balance_chf: str | None = None
    used_value_chf: str = "0.00"
    difference_chf: str = "0.00"
    last_manual_reconciliation: str | None = None
    last_imported_booking: str | None = None
    status: str

class CashPositionDetail(CashPosition):
    last_change: str | None = None
    history: list[CashSnapshot] = []
    available_actions: list[ActionItem]

class InstrumentSearchCandidate(BaseModel):
    candidate_id: str
    label: str
    asset_class: str
    isin: str = ""
    ticker: str = ""
    exchange: str = ""
    currency: str = ""
    provider: str = ""
    provider_symbol: str = ""
    exchange_name: str = ""
    mic: str = ""
    country: str = ""
    security_type: str = ""
    last_price: str | None = None
    price_currency: str | None = None
    price_date: str | None = None
    confidence_label: str
    review_required: bool

class InstrumentSearchRequest(BaseModel):
    asset_class: str
    query: str
    currency: str | None = None
    exchange: str | None = None
    country: str | None = None
    main_listing_only: bool = True
    hide_cdr_adr_derivatives: bool = True

class ProviderSearchResponse(BaseModel):
    candidates: list[InstrumentSearchCandidate]
    warnings: list[str] = []
    selection_required: bool = True

class CleanupPreviewResponse(BaseModel):
    accounts: int
    instruments: int
    transactions: int
    alerts: int
    manual_positions_preserved: int
    warnings: list[str] = []

class GenericConfirmRequest(BaseModel):
22:class CashCalculationResult:


sed -n '1,120p' src/jarvis_finance/ledger/cash.py


Output:
Chunk ID: d93fa0
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1064
Output:
from __future__ import annotations

from dataclasses import dataclass, field
from decimal import Decimal
from sqlite3 import Connection

from jarvis_finance.audit.log import record_audit_event
from jarvis_finance.imports.common import stable_id, utc_now
from jarvis_finance.quality.alerts import create_alert

@dataclass
class CashBalance:
    account_id: str
    currency: str
    amount_original: Decimal = Decimal("0")
    amount_chf: Decimal | None = Decimal("0")
    quality_status: str = "ok"

@dataclass
class CashCalculationResult:
    balances: dict[tuple[str, str], CashBalance] = field(default_factory=dict)
    negative_cash_warnings: list[str] = field(default_factory=list)

def _d(value: object, default: str = "0") -> Decimal:
    if value is None or str(value).strip() == "":
        return Decimal(default)
    return Decimal(str(value))

def _signed_cash_delta(row) -> tuple[Decimal, Decimal | None]:
    t = row["transaction_type"]
    gross = _d(row["gross_amount_original"])
    net = _d(row["net_amount_original"]) if row["net_amount_original"] is not None else None
    fee = _d(row["fee_original"])
    tax = _d(row["tax_original"])
    fx = _d(row["fx_rate_to_chf"], "1") if row["fx_rate_to_chf"] is not None else None

    if t == "initial_cash_snapshot":
        original = net if net is not None else gross
    elif t == "cash_deposit":
        original = net if net is not None else gross
    elif t == "cash_withdrawal":
        original = -(net if net is not None else gross)
    elif t == "buy":
        original = -(net if net is not None else gross + fee + tax)
    elif t in {"sell", "partial_sell", "full_sell"}:
        original = net if net is not None else gross - fee - tax
    elif t in {"dividend", "etf_distribution"}:
        original = net if net is not None else gross - tax - fee
    elif t in {"fee", "tax"}:
        original = -(net if net is not None else gross or fee or tax)
    elif t == "fx_conversion":
        original = net if net is not None else gross
    elif t == "manual_cash_correction":
        original = net if net is not None else gross
    else:
        original = Decimal("0")
    chf = original * fx if fx is not None else None
    return original, chf

def calculate_cash_balances(
    conn: Connection, *, as_of_date: str | None = None, persist_alerts: bool = True
) -> CashCalculationResult:
    result = CashCalculationResult()
    params: tuple[object, ...] = ()
    where = "WHERE COALESCE(is_voided, 0) = 0"
    if as_of_date:
        where += " AND trade_date <= ?"
        params = (as_of_date,)
    rows = conn.execute(
        f"""
        SELECT * FROM transactions
        {where}
        ORDER BY account_id, currency_original, trade_date, created_at, transaction_id
        """,
        params,
    ).fetchall()
    for row in rows:
        account_id = row["account_id"]
        currency = row["currency_original"]
        key = (account_id, currency)
        balance = result.balances.setdefault(key, CashBalance(account_id, currency))
        original, chf = _signed_cash_delta(row)
        balance.amount_original += original
        if chf is None:
            balance.amount_chf = None
            balance.quality_status = "incomplete"
        elif balance.amount_chf is not None:
            balance.amount_chf += chf
    for key, balance in result.balances.items():
        if balance.amount_original < 0:
            msg = f"Negative cash balance for account={balance.account_id} currency={balance.currency}: {balance.amount_original}"
            result.negative_cash_warnings.append(msg)
            if persist_alerts:
                create_alert(
                    conn,
                    priority="warnung",
                    category="cash",
                    entity_type="account",
                    entity_id=balance.account_id,
                    rule_id="negative_cash",
                    message=msg,
                    evidence={"currency": balance.currency, "amount_original": str(balance.amount_original)},
                )
    if persist_alerts:
        conn.commit()
    return result

def apply_manual_cash_correction(
    conn: Connection,
    *,
    account_id: str,
    currency: str,
    amount: Decimal,
    note: str,


grep -R "vue_equity_dividend\|vue_equity_sale" -n src/jarvis_finance/services src/jarvis_finance | head -80


Output:
Chunk ID: e8dcb7
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1099
Output:
grep: src/jarvis_finance/services/__pycache__/cash_service.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/manual_entry_service.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/cash_service.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/manual_entry_service.cpython-311.pyc: binary file matches
src/jarvis_finance/services/manual_entry_service.py:916:        VALUES (?, 'sell', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'vue_equity_sale', 1, ?, ?, ?)
src/jarvis_finance/services/manual_entry_service.py:919:        conn.execute("INSERT INTO cash_balances(cash_balance_id, account_id, balance_date, currency, amount_original, fx_rate_to_chf, amount_chf, source_type, quality_status, notes, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", (_uuid("cash"), request.cash_account_id, request.trade_date, request.currency.upper(), _format_decimal(net), fx_rate, net_chf, f"vue_equity_sale:{tx_id}", "ok" if fx_status != "missing" else "missing_fx", request.note, ts))
src/jarvis_finance/services/manual_entry_service.py:955:        VALUES (?, 'dividend', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'vue_equity_dividend', 1, ?, ?, ?)
src/jarvis_finance/services/manual_entry_service.py:957:    conn.execute("INSERT INTO cash_balances(cash_balance_id, account_id, balance_date, currency, amount_original, fx_rate_to_chf, amount_chf, source_type, quality_status, notes, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, 'vue_equity_dividend', ?, ?, ?)", (_uuid("cash"), request.cash_account_id, request.payment_date, request.currency.upper(), _format_decimal(net), fx_rate, net_chf, "ok" if fx_status != "missing" else "missing_fx", request.note, ts))
src/jarvis_finance/services/cash_service.py:228:              AND (source_type LIKE 'vue_equity_sale:%'
src/jarvis_finance/services/cash_service.py:229:                   OR source_type='vue_equity_dividend')
src/jarvis_finance/services/cash_service.py:237:            if source_type.startswith("vue_equity_sale:")
src/jarvis_finance/services/cash_service.py:242:        if source_type == "vue_equity_dividend":
src/jarvis_finance/services/cash_service.py:245:                    WHERE account_id=? AND source_type='vue_equity_dividend'
src/jarvis_finance/services/cash_service.py:381:                        ("vue_equity_sale:", "vue_equity_dividend")
src/jarvis_finance/services/manual_entry_service.py:916:        VALUES (?, 'sell', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'vue_equity_sale', 1, ?, ?, ?)
src/jarvis_finance/services/manual_entry_service.py:919:        conn.execute("INSERT INTO cash_balances(cash_balance_id, account_id, balance_date, currency, amount_original, fx_rate_to_chf, amount_chf, source_type, quality_status, notes, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", (_uuid("cash"), request.cash_account_id, request.trade_date, request.currency.upper(), _format_decimal(net), fx_rate, net_chf, f"vue_equity_sale:{tx_id}", "ok" if fx_status != "missing" else "missing_fx", request.note, ts))
src/jarvis_finance/services/manual_entry_service.py:955:        VALUES (?, 'dividend', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'vue_equity_dividend', 1, ?, ?, ?)
src/jarvis_finance/services/manual_entry_service.py:957:    conn.execute("INSERT INTO cash_balances(cash_balance_id, account_id, balance_date, currency, amount_original, fx_rate_to_chf, amount_chf, source_type, quality_status, notes, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, 'vue_equity_dividend', ?, ?, ?)", (_uuid("cash"), request.cash_account_id, request.payment_date, request.currency.upper(), _format_decimal(net), fx_rate, net_chf, "ok" if fx_status != "missing" else "missing_fx", request.note, ts))
src/jarvis_finance/services/cash_service.py:228:              AND (source_type LIKE 'vue_equity_sale:%'
src/jarvis_finance/services/cash_service.py:229:                   OR source_type='vue_equity_dividend')
src/jarvis_finance/services/cash_service.py:237:            if source_type.startswith("vue_equity_sale:")
src/jarvis_finance/services/cash_service.py:242:        if source_type == "vue_equity_dividend":
src/jarvis_finance/services/cash_service.py:245:                    WHERE account_id=? AND source_type='vue_equity_dividend'
src/jarvis_finance/services/cash_service.py:381:                        ("vue_equity_sale:", "vue_equity_dividend")


sed -n '880,970p' src/jarvis_finance/services/manual_entry_service.py


Output:
Chunk ID: c9016c
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 2096
Output:
    fees = _decimal_non_negative(request.fees_original, "fees_original")
    current = _current_equity_quantity(conn, account_id=account_id, instrument_id=instrument_id)
    if quantity > current:
        raise HTTPException(status_code=422, detail="Verkauf würde Bestand negativ machen")
    gross = quantity * price
    net = gross - fees
    if net < 0:
        raise HTTPException(status_code=422, detail="fees exceed gross proceeds")
    currency = request.currency.upper()
    fx_status, fx_rate, _fx_source, fx_warning = _fx_for_explicit_save(conn, currency=currency, trade_date=request.trade_date)
    amount_chf = _chf_amount(_format_decimal(net), Decimal(fx_rate) if fx_rate else None)
    avg = _weighted_average_cost(conn, account_id=account_id, instrument_id=instrument_id)
    warnings = [fx_warning] if fx_warning else []
    if avg is None:
        warnings.append("Einstand unvollständig: realisierter P&L nur eingeschränkt verfügbar.")
    return PreviewResponse(preview_id=_uuid("preview"), asset_class="equity", summary=f"Verkauf {quantity} · Erlös {currency} {_format_decimal(net)}", amount_chf=amount_chf, fx_status=fx_status, warnings=warnings)

def confirm_equity_sell(conn: Connection, request: EquitySellConfirmRequest) -> ConfirmResponse:
    if not request.confirm:
        raise HTTPException(status_code=400, detail="Explicit confirm required")
    preview = preview_equity_sell(conn, request)
    account_id, instrument_id = _position_ids(request.position_id)
    quantity = _decimal(request.quantity, "quantity")
    price = _decimal(request.price_original, "price_original")
    fees = _decimal_non_negative(request.fees_original, "fees_original")
    gross = quantity * price
    net = gross - fees
    fx_status, fx_rate, fx_source, _ = _fx_for_explicit_save(conn, currency=request.currency, trade_date=request.trade_date)
    gross_chf = _chf_amount(_format_decimal(gross), Decimal(fx_rate) if fx_rate else None)
    fee_chf = _chf_amount(_format_decimal(fees), Decimal(fx_rate) if fx_rate else None)
    net_chf = _chf_amount(_format_decimal(net), Decimal(fx_rate) if fx_rate else None)
    tx_id = _uuid("tx")
    ts = _now()
    conn.execute("""
        INSERT INTO transactions(transaction_id, transaction_type, account_id, instrument_id, trade_date, quantity, price_original, gross_amount_original, fee_original, net_amount_original, currency_original, fx_rate_to_chf, fx_source, fx_status, gross_amount_chf, fee_chf, net_amount_chf, source_type, is_confirmed, quality_status, notes, created_at)
        VALUES (?, 'sell', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'vue_equity_sale', 1, ?, ?, ?)
    """, (tx_id, account_id, instrument_id, request.trade_date, _format_decimal(-quantity), _format_decimal(price), _format_decimal(gross), _format_decimal(fees), _format_decimal(net), request.currency.upper(), fx_rate, fx_source, fx_status, gross_chf, fee_chf, net_chf, "ok" if fx_status != "missing" else "missing_fx", request.note, ts))
    if _cash_account_exists(conn, request.cash_account_id):
        conn.execute("INSERT INTO cash_balances(cash_balance_id, account_id, balance_date, currency, amount_original, fx_rate_to_chf, amount_chf, source_type, quality_status, notes, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", (_uuid("cash"), request.cash_account_id, request.trade_date, request.currency.upper(), _format_decimal(net), fx_rate, net_chf, f"vue_equity_sale:{tx_id}", "ok" if fx_status != "missing" else "missing_fx", request.note, ts))
    audit_id = _audit(conn, action="equity_sell_confirm", entity_type="position", entity_id=request.position_id, payload={**request.model_dump(), "net_amount_original": _format_decimal(net), "gross_amount_original": _format_decimal(gross)}, note=request.note, quality_status="ok" if fx_status != "missing" else "missing_fx")
    conn.commit()
    return ConfirmResponse(status="confirmed", entity_id=tx_id, audit_id=audit_id, message="Verkauf bestätigt · Audit geschrieben")

def preview_equity_dividend(conn: Connection, request: EquityDividendPreviewRequest) -> PreviewResponse:
    _position_ids(request.position_id)
    gross = _decimal(request.gross_amount, "gross_amount")
    taxes = _decimal_non_negative(request.swiss_tax, "swiss_tax") + _decimal_non_negative(request.foreign_tax, "foreign_tax") + _decimal_non_negative(request.other_deductions, "other_deductions")
    net = gross - taxes
    if net < 0:
        raise HTTPException(status_code=422, detail="deductions exceed gross dividend")
    if not _cash_account_exists(conn, request.cash_account_id):
        raise HTTPException(status_code=404, detail="Cash account not found")
    fx_status, fx_rate, _fx_source, fx_warning = _fx_for_explicit_save(conn, currency=request.currency, trade_date=request.payment_date)
    warnings = [fx_warning] if fx_warning else []
    return PreviewResponse(preview_id=_uuid("preview"), asset_class="income", summary=f"Dividende netto {request.currency.upper()} {_format_decimal(net)}", amount_chf=_chf_amount(_format_decimal(net), Decimal(fx_rate) if fx_rate else None), fx_status=fx_status, warnings=warnings)

def confirm_equity_dividend(conn: Connection, request: EquityDividendConfirmRequest) -> ConfirmResponse:
    if not request.confirm:
        raise HTTPException(status_code=400, detail="Explicit confirm required")
    preview = preview_equity_dividend(conn, request)
    account_id, instrument_id = _position_ids(request.position_id)
    gross = _decimal(request.gross_amount, "gross_amount")
    taxes = _decimal_non_negative(request.swiss_tax, "swiss_tax") + _decimal_non_negative(request.foreign_tax, "foreign_tax") + _decimal_non_negative(request.other_deductions, "other_deductions")
    net = gross - taxes
    fx_status, fx_rate, fx_source, _ = _fx_for_explicit_save(conn, currency=request.currency, trade_date=request.payment_date)
    gross_chf = _chf_amount(_format_decimal(gross), Decimal(fx_rate) if fx_rate else None)
    tax_chf = _chf_amount(_format_decimal(taxes), Decimal(fx_rate) if fx_rate else None)
    net_chf = _chf_amount(_format_decimal(net), Decimal(fx_rate) if fx_rate else None)
    tx_id = _uuid("tx")
    ts = _now()
    conn.execute("""
        INSERT INTO transactions(transaction_id, transaction_type, account_id, instrument_id, trade_date, gross_amount_original, tax_original, net_amount_original, currency_original, fx_rate_to_chf, fx_source, fx_status, gross_amount_chf, tax_chf, net_amount_chf, source_type, is_confirmed, quality_status, notes, created_at)
        VALUES (?, 'dividend', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'vue_equity_dividend', 1, ?, ?, ?)
    """, (tx_id, account_id, instrument_id, request.payment_date, _format_decimal(gross), _format_decimal(taxes), _format_decimal(net), request.currency.upper(), fx_rate, fx_source, fx_status, gross_chf, tax_chf, net_chf, "ok" if fx_status != "missing" else "missing_fx", request.note, ts))
    conn.execute("INSERT INTO cash_balances(cash_balance_id, account_id, balance_date, currency, amount_original, fx_rate_to_chf, amount_chf, source_type, quality_status, notes, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, 'vue_equity_dividend', ?, ?, ?)", (_uuid("cash"), request.cash_account_id, request.payment_date, request.currency.upper(), _format_decimal(net), fx_rate, net_chf, "ok" if fx_status != "missing" else "missing_fx", request.note, ts))
    audit_id = _audit(conn, action="equity_dividend_confirm", entity_type="position", entity_id=request.position_id, payload={**request.model_dump(), "net_amount_original": _format_decimal(net), "tax_original": _format_decimal(taxes)}, note=request.note, quality_status="ok" if fx_status != "missing" else "missing_fx")
    conn.commit()
    return ConfirmResponse(status="confirmed", entity_id=tx_id, audit_id=audit_id, message="Dividende bestätigt · Audit geschrieben")

def cleanup_review_artifacts_preview(conn: Connection) -> CleanupPreviewResponse:
    plan = identify_review_test_equity_artifacts(conn)
    warnings = []
    if plan.artifact_count:
        warnings.append("Review-/Test-Artefakte werden archiviert; manuelle Positionen bleiben erhalten.")
    return CleanupPreviewResponse(accounts=len(plan.account_ids), instruments=len(plan.instrument_ids), transactions=len(plan.transaction_ids), alerts=len(plan.alert_ids), manual_positions_preserved=plan.manual_position_count, warnings=warnings)


grep -R "quality_status.*fresh" -n src/jarvis_finance/services/portfolio_analytics.py src/jarvis_finance | head -40 && grep -R "summary_json" -n src/jarvis_finance/services/portfolio_analytics.py | head -20


Output:
Chunk ID: ec1cc0
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 5082
Output:
grep: src/jarvis_finance/ledger/__pycache__/positions.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/ledger/__pycache__/positions.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/storage/__pycache__/migrations.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/storage/__pycache__/schema.cpython-311.pyc: binary file matches
src/jarvis_finance/services/portfolio_analytics.py:162:              AND quality_status='fresh' AND error_message IS NULL
src/jarvis_finance/services/portfolio_analytics.py:574:                "as_of": quote_as_of.isoformat(), "quality_status": "fresh" if 0 <= _business_day_age(quote_as_of, effective) <= 2 else "stale",
src/jarvis_finance/services/portfolio_analytics.py:685:                            rate_type="close", quality_status="fresh", fetched_at=now, run_id=run_id,
src/jarvis_finance/services/portfolio_analytics.py:970:        "as_of": latest["as_of"], "status": latest["quality_status"], "freshness": freshness, "notice": notice,
src/jarvis_finance/ledger/positions.py:69:            WHERE instrument_id=? AND price_date <= ? AND quality_status IN ('fresh','ok')
src/jarvis_finance/ledger/positions.py:77:        WHERE instrument_id=? AND quality_status IN ('fresh','ok')
src/jarvis_finance/market/providers.py:26:    quality_status: str = "fresh"
src/jarvis_finance/market/providers.py:194:    return bool(latest and latest["quality_status"] == "fresh" and not is_price_stale(latest["fetched_at"], max_age_seconds=max_age_seconds))
src/jarvis_finance/market/providers.py:205:        has_any = latest is not None and latest["price"] not in (None, "") and latest["quality_status"] == "fresh"
src/jarvis_finance/market/providers.py:206:        is_fresh = bool(latest and latest["quality_status"] == "fresh" and not is_price_stale(latest["fetched_at"], max_age_seconds=max_age_seconds))
src/jarvis_finance/market/providers.py:207:        is_stale = bool(latest and latest["quality_status"] == "fresh" and is_price_stale(latest["fetched_at"], max_age_seconds=max_age_seconds))
src/jarvis_finance/market/providers.py:257:        if latest and latest["quality_status"] == "fresh" and not is_price_stale(latest["fetched_at"], max_age_seconds=max_age_seconds):
src/jarvis_finance/market/providers.py:277:            if quote.price is not None and quote.quality_status == "fresh":
src/jarvis_finance/market/providers.py:290:            if (quote.price is None or quote.quality_status != "fresh") and not dry_run:
src/jarvis_finance/storage/schema.py:1:INITIAL_SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS schema_migrations (\n    version INTEGER PRIMARY KEY,\n    name TEXT NOT NULL,\n    applied_at TEXT NOT NULL,\n    checksum TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS platforms (\n    platform_id TEXT PRIMARY KEY,\n    name TEXT NOT NULL UNIQUE,\n    platform_type TEXT NOT NULL,\n    country TEXT,\n    default_currency TEXT NOT NULL DEFAULT 'CHF',\n    is_active INTEGER NOT NULL DEFAULT 1,\n    notes TEXT,\n    created_at TEXT NOT NULL,\n    updated_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS accounts (\n    account_id TEXT PRIMARY KEY,\n    platform_id TEXT NOT NULL REFERENCES platforms(platform_id),\n    account_name TEXT NOT NULL,\n    account_type TEXT NOT NULL,\n    currency TEXT NOT NULL DEFAULT 'CHF',\n    performance_included INTEGER NOT NULL DEFAULT 1,\n    is_health_reserve INTEGER NOT NULL DEFAULT 0,\n    target_cash_min_chf NUMERIC,\n    target_cash_max_chf NUMERIC,\n    is_active INTEGER NOT NULL DEFAULT 1,\n    notes TEXT,\n    created_at TEXT NOT NULL,\n    updated_at TEXT,\n    UNIQUE(platform_id, account_name)\n);\n\nCREATE TABLE IF NOT EXISTS instruments (\n    instrument_id TEXT PRIMARY KEY,\n    asset_class TEXT NOT NULL,\n    name TEXT NOT NULL,\n    ticker TEXT,\n    isin TEXT,\n    exchange TEXT,\n    currency TEXT NOT NULL,\n    country TEXT,\n    sector TEXT,\n    industry TEXT,\n    provider_symbol TEXT,\n    data_provider_primary TEXT,\n    position_category TEXT,\n    ter TEXT,\n    distribution_policy TEXT,\n    index_name TEXT,\n    fund_domicile TEXT,\n    benchmark TEXT,\n    data_provider_fallback TEXT,\n    is_active INTEGER NOT NULL DEFAULT 1,\n    notes TEXT,\n    created_at TEXT NOT NULL,\n    updated_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS transactions (\n    transaction_id TEXT PRIMARY KEY,\n    transaction_type TEXT NOT NULL,\n    account_id TEXT NOT NULL REFERENCES accounts(account_id),\n    instrument_id TEXT REFERENCES instruments(instrument_id),\n    trade_date TEXT NOT NULL,\n    settlement_date TEXT,\n    quantity TEXT,\n    price_original TEXT,\n    gross_amount_original TEXT,\n    fee_original TEXT DEFAULT '0',\n    tax_original TEXT DEFAULT '0',\n    net_amount_original TEXT,\n    currency_original TEXT NOT NULL,\n    fx_rate_to_chf TEXT,\n    fx_source TEXT,\n    fx_status TEXT NOT NULL DEFAULT 'ok',\n    gross_amount_chf TEXT,\n    fee_chf TEXT,\n    tax_chf TEXT,\n    net_amount_chf TEXT,\n    source_type TEXT NOT NULL,\n    source_id TEXT,\n    external_transaction_id TEXT,\n    row_hash TEXT,\n    is_confirmed INTEGER NOT NULL DEFAULT 1,\n    quality_status TEXT NOT NULL DEFAULT 'ok',\n    notes TEXT,\n    created_at TEXT NOT NULL,\n    updated_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS positions_snapshot (\n    position_snapshot_id TEXT PRIMARY KEY,\n    snapshot_date TEXT NOT NULL,\n    account_id TEXT NOT NULL REFERENCES accounts(account_id),\n    platform_id TEXT NOT NULL REFERENCES platforms(platform_id),\n    instrument_id TEXT NOT NULL REFERENCES instruments(instrument_id),\n    quantity NUMERIC NOT NULL,\n    average_cost_original NUMERIC,\n    cost_basis_original NUMERIC,\n    cost_basis_chf NUMERIC,\n    market_price_original NUMERIC,\n    market_value_original NUMERIC,\n    market_fx_rate_to_chf NUMERIC,\n    market_value_chf NUMERIC,\n    unrealized_price_pnl_chf NUMERIC,\n    unrealized_fx_pnl_chf NUMERIC,\n    realized_pnl_chf NUMERIC,\n    income_chf NUMERIC,\n    fees_chf NUMERIC,\n    taxes_chf NUMERIC,\n    total_return_chf NUMERIC,\n    portfolio_weight_pct NUMERIC,\n    category TEXT,\n    data_quality_status TEXT NOT NULL DEFAULT 'ok',\n    created_at TEXT NOT NULL,\n    UNIQUE(snapshot_date, account_id, instrument_id)\n);\n\nCREATE TABLE IF NOT EXISTS cash_balances (\n    cash_balance_id TEXT PRIMARY KEY,\n    account_id TEXT NOT NULL REFERENCES accounts(account_id),\n    balance_date TEXT NOT NULL,\n    currency TEXT NOT NULL,\n    amount_original NUMERIC NOT NULL,\n    fx_rate_to_chf NUMERIC,\n    amount_chf NUMERIC,\n    source_type TEXT NOT NULL,\n    quality_status TEXT NOT NULL DEFAULT 'ok',\n    notes TEXT,\n    created_at TEXT NOT NULL,\n    UNIQUE(account_id, balance_date, currency, source_type)\n);\n\nCREATE TABLE IF NOT EXISTS fx_rates (\n    fx_rate_id TEXT PRIMARY KEY,\n    base_currency TEXT NOT NULL,\n    quote_currency TEXT NOT NULL DEFAULT 'CHF',\n    rate_date TEXT NOT NULL,\n    rate_timestamp TEXT,\n    rate NUMERIC NOT NULL,\n    provider TEXT NOT NULL,\n    rate_type TEXT NOT NULL,\n    quality_status TEXT NOT NULL DEFAULT 'ok',\n    created_at TEXT NOT NULL,\n    UNIQUE(base_currency, quote_currency, rate_date, provider, rate_type)\n);\n\nCREATE TABLE IF NOT EXISTS market_prices (\n    market_price_id TEXT PRIMARY KEY,\n    instrument_id TEXT NOT NULL REFERENCES instruments(instrument_id),\n    price_date TEXT NOT NULL,\n    price_timestamp TEXT,\n    open NUMERIC,\n    high NUMERIC,\n    low NUMERIC,\n    close NUMERIC NOT NULL,\n    adjusted_close NUMERIC,\n    currency TEXT NOT NULL,\n    provider TEXT NOT NULL,\n    provider_symbol TEXT,\n    quality_status TEXT NOT NULL DEFAULT 'ok',\n    created_at TEXT NOT NULL,\n    UNIQUE(instrument_id, price_date, provider)\n);\n\nCREATE TABLE IF NOT EXISTS crypto_wallets (\n    wallet_id TEXT PRIMARY KEY,\n    wallet_name TEXT NOT NULL UNIQUE,\n    wallet_type TEXT NOT NULL,\n    platform_provider TEXT,\n    network_chain TEXT,\n    wallet_address TEXT,\n    owner TEXT,\n    is_active INTEGER NOT NULL DEFAULT 1,\n    last_verified_at TEXT,\n    notes TEXT,\n    created_at TEXT NOT NULL,\n    updated_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS crypto_assets (\n    asset_id TEXT PRIMARY KEY,\n    coin_name TEXT NOT NULL,\n    symbol TEXT NOT NULL,\n    coingecko_id TEXT UNIQUE,\n    network_chain_default TEXT,\n    is_stablecoin INTEGER NOT NULL DEFAULT 0,\n    price_provider_primary TEXT NOT NULL DEFAULT 'CoinGecko',\n    price_provider_fallback TEXT,\n    is_active INTEGER NOT NULL DEFAULT 1,\n    notes TEXT,\n    created_at TEXT NOT NULL,\n    updated_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS crypto_holdings (\n    crypto_holding_id TEXT PRIMARY KEY,\n    asset_id TEXT NOT NULL REFERENCES crypto_assets(asset_id),\n    wallet_id TEXT NOT NULL REFERENCES crypto_wallets(wallet_id),\n    quantity TEXT NOT NULL,\n    acquisition_source TEXT,\n    last_verified_at TEXT,\n    verification_status TEXT NOT NULL DEFAULT 'unverified',\n    legacy_snapshot_value_original TEXT,\n    legacy_snapshot_value_chf TEXT,\n    legacy_snapshot_currency TEXT,\n    legacy_snapshot_date TEXT,\n    notes TEXT,\n    created_at TEXT NOT NULL,\n    updated_at TEXT,\n    UNIQUE(asset_id, wallet_id)\n);\n\nCREATE TABLE IF NOT EXISTS crypto_transactions (\n    crypto_transaction_id TEXT PRIMARY KEY,\n    transaction_id TEXT REFERENCES transactions(transaction_id),\n    transaction_type TEXT NOT NULL,\n    asset_id TEXT NOT NULL REFERENCES crypto_assets(asset_id),\n    quantity TEXT NOT NULL,\n    price_original TEXT,\n    currency_original TEXT,\n    gross_amount_original TEXT,\n    fee_quantity TEXT,\n    fee_original TEXT,\n    fee_currency TEXT,\n    fx_rate_to_chf TEXT,\n    fx_source TEXT,\n    amount_chf TEXT,\n    from_wallet_id TEXT REFERENCES crypto_wallets(wallet_id),\n    to_wallet_id TEXT REFERENCES crypto_wallets(wallet_id),\n    transaction_datetime TEXT NOT NULL,\n    tx_hash TEXT,\n    source TEXT NOT NULL,\n    confirmation_status TEXT NOT NULL DEFAULT 'confirmed',\n    parse_confidence NUMERIC,\n    original_input_text TEXT,\n    notes TEXT,\n    created_at TEXT NOT NULL,\n    updated_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS crypto_prices (\n    crypto_price_id TEXT PRIMARY KEY,\n    asset_id TEXT NOT NULL REFERENCES crypto_assets(asset_id),\n    coingecko_id TEXT,\n    price_currency TEXT NOT NULL,\n    price TEXT NOT NULL,\n    provider TEXT NOT NULL DEFAULT 'CoinGecko',\n    provider_timestamp TEXT,\n    fetched_at TEXT NOT NULL,\n    quality_status TEXT NOT NULL DEFAULT 'fresh',\n    error_message TEXT\n);\n\nCREATE TABLE IF NOT EXISTS watchlist (\n    watchlist_id TEXT PRIMARY KEY,\n    instrument_id TEXT REFERENCES instruments(instrument_id),\n    crypto_asset_id TEXT REFERENCES crypto_assets(asset_id),\n    name TEXT NOT NULL,\n    asset_class TEXT NOT NULL,\n    reason TEXT NOT NULL,\n    target_entry_price NUMERIC,\n    target_entry_currency TEXT,\n    desired_position_size_chf NUMERIC,\n    desired_weight_pct NUMERIC,\n    trigger_rules TEXT,\n    risk_notes TEXT,\n    investment_case TEXT,\n    bear_case TEXT,\n    sources TEXT,\n    status TEXT NOT NULL DEFAULT 'active',\n    next_review_date TEXT,\n    created_at TEXT NOT NULL,\n    updated_at TEXT\n);\n\nCREATE TABLE IF NOT EXISTS reports (\n    report_id TEXT PRIMARY KEY,\n    report_type TEXT NOT NULL,\n    title TEXT NOT NULL,\n    period_start TEXT,\n    period_end TEXT,\n    generated_at TEXT NOT NULL,\n    file_path TEXT,\n    format TEXT NOT NULL,\n    data_quality_status TEXT NOT NULL DEFAULT 'ok',\n    summary_json TEXT,\n    created_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS alerts (\n    alert_id TEXT PRIMARY KEY,\n    priority TEXT NOT NULL,\n    category TEXT NOT NULL,\n    entity_type TEXT,\n    entity_id TEXT,\n    rule_id TEXT,\n    message TEXT NOT NULL,\n    evidence_json TEXT,\n    status TEXT NOT NULL DEFAULT 'active',\n    created_at TEXT NOT NULL,\n    resolved_at TEXT,\n    muted_until TEXT,\n    last_seen_at TEXT,\n    occurrence_count INTEGER NOT NULL DEFAULT 1,\n    fingerprint TEXT,\n    dedup_key TEXT\n);\n\nCREATE INDEX IF NOT EXISTS idx_alerts_dedup ON alerts(dedup_key, status);\n\nCREATE TABLE IF NOT EXISTS audit_log (\n    audit_id TEXT PRIMARY KEY,\n    timestamp TEXT NOT NULL,\n    source TEXT NOT NULL,\n    action TEXT NOT NULL,\n    entity_type TEXT NOT NULL,\n    entity_id TEXT NOT NULL,\n    old_values_json TEXT,\n    new_values_json TEXT,\n    user_text_note TEXT,\n    original_input_text TEXT,\n    confirmed INTEGER NOT NULL DEFAULT 1,\n    confirmation_timestamp TEXT,\n    auto_parsed INTEGER NOT NULL DEFAULT 0,\n    parse_confidence NUMERIC,grep: src/jarvis_finance/dashboard/__pycache__/data.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/dashboard/__pycache__/data.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/market_data/__pycache__/prices.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/market_data/__pycache__/prices.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_data.cpython-311.pyc: binary file matches
\n    created_by TEXT NOT NULL DEFAULT 'system',\n    quality_status TEXT NOT NULL DEFAULT 'ok',\n    created_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS import_sessions (\n    import_session_id TEXT PRIMARY KEY,\n    import_type TEXT NOT NULL,\n    source_filename TEXT NOT NULL,\n    source_hash TEXT,\n    started_at TEXT NOT NULL,\n    finished_at TEXT,\n    status TEXT NOT NULL,\n    rows_total INTEGER DEFAULT 0,\n    rows_imported INTEGER DEFAULT 0,\n    rows_failed INTEGER DEFAULT 0,\n    errors_json TEXT,\n    notes TEXT\n);\n\nCREATE TABLE IF NOT EXISTS decision_journal (\n    decision_id TEXT PRIMARY KEY,\n    decision_date TEXT NOT NULL,\n    decision_type TEXT NOT NULL,\n    entity_type TEXT,\n    entity_id TEXT,\n    system_recommendation TEXT,\n    human_decision TEXT NOT NULL,\n    rationale TEXT NOT NULL,\n    investment_case TEXT,\n    risks TEXT,\n    exit_rule TEXT,\n    alternatives_considered TEXT,\n    sources TEXT,\n    review_date TEXT,\n    outcome_status TEXT,\n    outcome_return_chf NUMERIC,\n    created_at TEXT NOT NULL,\n    updated_at TEXT\n);\n\nCREATE INDEX IF NOT EXISTS idx_accounts_platform_id ON accounts(platform_id);\nCREATE INDEX IF NOT EXISTS idx_transactions_account_date ON transactions(account_id, trade_date);\nCREATE INDEX IF NOT EXISTS idx_transactions_instrument_date ON transactions(instrument_id, trade_date);\nCREATE INDEX IF NOT EXISTS idx_transactions_type ON transactions(transaction_type);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_transactions_external_id ON transactions(external_transaction_id) WHERE external_transaction_id IS NOT NULL AND external_transaction_id != '';\nCREATE UNIQUE INDEX IF NOT EXISTS idx_transactions_row_hash ON transactions(row_hash) WHERE row_hash IS NOT NULL AND row_hash != '';\nCREATE INDEX IF NOT EXISTS idx_crypto_transactions_asset_datetime ON crypto_transactions(asset_id, transaction_datetime);\nCREATE INDEX IF NOT EXISTS idx_alerts_priority_status ON alerts(priority, status);\nCREATE INDEX IF NOT EXISTS idx_audit_entity ON audit_log(entity_type, entity_id);\n"
src/jarvis_finance/storage/migrations.py:1497:            quality_status TEXT NOT NULL DEFAULT 'fresh',
src/jarvis_finance/quality/data_quality.py:70:    return bool(latest and latest["quality_status"] == "fresh" and latest["price"] not in (None, "") and not _is_stale(latest["fetched_at"], max_age_seconds=max_age_seconds))
src/jarvis_finance/dashboard/data.py:205:    if item.get("quality_status") == "fresh" and is_price_stale(ts, max_age_seconds=max_age_seconds):
src/jarvis_finance/dashboard/data.py:588:                WHERE instrument_id=i.instrument_id AND quality_status IN ('fresh','ok')
src/jarvis_finance/market_data/prices.py:27:    quality_status: str = "fresh"
src/jarvis_finance/market_data/prices.py:150:                        quality_status="fresh",
src/jarvis_finance/market_data/prices.py:164:        return EquityPriceQuote(provider_symbol=symbol, currency=currency or "USD", close=close, provider=self.name, price_timestamp=utc_now(), quality_status="fresh")
src/jarvis_finance/market_data/prices.py:224:        return EquityPriceQuote(provider_symbol=symbol, currency=currency or "USD", close=price, provider=self.name, price_timestamp=utc_now(), quality_status="fresh")
src/jarvis_finance/market_data/prices.py:249:        return EquityPriceQuote(provider_symbol=symbol, currency=currency or "USD", close=price, provider=self.name, price_timestamp=ts, quality_status="fresh")
src/jarvis_finance/market_data/prices.py:281:        return EquityPriceQuote(provider_symbol=symbol, currency="USD", close=price, provider=self.name, price_timestamp=utc_now(), quality_status="fresh")
src/jarvis_finance/market_data/prices.py:303:        return EquityPriceQuote(provider_symbol=symbol, currency=str(row.get("currency") or "USD").upper(), close=price, provider=self.name, price_timestamp=utc_now(), quality_status="fresh")
src/jarvis_finance/market_data/prices.py:356:            return EquityPriceQuote(provider_symbol=symbol, currency=currency, close=close, provider=self.name, provider_market=market, prgrep: src/jarvis_finance/services/__pycache__/market_service.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/manual_entry_service.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_analytics.cpython-312.pyc: binary file matches
grep: src/jarvis_finance/services/__pycache__/portfolio_analytics.cpython-311.pyc: binary file matches
grep: src/jarvis_finance/fx/__pycache__/rates.cpython-311.pyc: binary file matches
ice_timestamp=timestamp, quality_status="fresh")
src/jarvis_finance/market_data/prices.py:377:            if quote.close is not None and quote.quality_status == "fresh":
src/jarvis_finance/market_data/prices.py:465:    quality_status: str = "fresh",
src/jarvis_finance/market_data/prices.py:477:    corp_status = _corporate_action_status(conn, instrument_id=instrument_id, price_date=price_date, provider=provider, close=close) if quality_status == "fresh" else "not_checked"
src/jarvis_finance/market_data/prices.py:521:    elif quality_status == "fresh":
src/jarvis_finance/market_data/prices.py:561:        latest = conn.execute("SELECT * FROM market_prices WHERE instrument_id=? AND quality_status='fresh' ORDER BY price_date DESC, created_at DESC LIMIT 1", (mapping["instrument_id"],)).fetchone()
src/jarvis_finance/market_data/cache.py:48:        upsert_equity_price_point(conn, instrument_id=instrument_id, timestamp=row["price_timestamp"] or row["price_date"], price=row["close"], currency=row["currency"] or "CHF", provider=row["provider"] or "local", provider_symbol=row["provider_symbol"], interval="eod", source_quality=row["quality_status"] or "fresh")
src/jarvis_finance/market_data/cache.py:58:        upsert_crypto_price_point(conn, asset_id=asset_id, timestamp=row["provider_timestamp"] or row["fetched_at"], price=row["price"], currency=row["price_currency"] or currency.upper(), provider=row["provider"] or "CoinGecko", provider_symbol=row["coingecko_id"], interval="quote", source_quality=row["quality_status"] or "fresh")
src/jarvis_finance/market_data/cache.py:87:    quality_status: str = "fresh",
src/jarvis_finance/cli/main.py:281:                    if response.quality_status == "fresh":
src/jarvis_finance/services/manual_entry_service.py:644:            WHERE instrument_id=i.instrument_id AND quality_status IN ('fresh','ok')
src/jarvis_finance/services/market_service.py:72:        quality_status=latest.quality_status if latest and latest.quality_status else ("fresh" if latest else "missing"),
src/jarvis_finance/services/market_service.py:141:               AND quality_status='fresh' AND error_message IS NULL
src/jarvis_finance/services/market_service.py:197:    return replace(quote, currency=actual_currency or expected_currency, price_timestamp=quote_date.isoformat(), quality_status="fresh")
grep: src/jarvis_finance/fx/__pycache__/rates.cpython-312.pyc: binary file matches
grep: write error: Broken pipe
733:                fx_coverage_pct,benchmark_coverage_pct,quality_status,reason_codes_json,summary_json,created_at)
946:    summary = json.loads(latest["summary_json"] or "{}")


sed -n '520,750p' src/jarvis_finance/services/portfolio_analytics.py