# First activation of managed-portfolio performance

Use this note when an intermittent-anchor managed portfolio is becoming return-capable for the first time through confirmed bank contributions and a narrowly attested coverage period.

## Period-boundary invariant

Treat an official opening valuation identified as a **calendar-day end anchor** as the state *after* every activity on that calendar day. For the following return interval, include external cashflows only when:

```text
opening_date < cashflow_date <= closing_date
```

Do not include a deposit dated on the opening day when the owner/source attests that it is already reflected in that opening value. Otherwise the engine subtracts it twice, understates investment result, and distorts XIRR/TTWROR.

This rule is appropriate only when the opening value is explicitly a day-end anchor. If source timing is unknown or intraday, stop and resolve timing instead of applying the exclusion by assumption.

Required regression pair:

1. opening-day deposit is absent from in-period cashflows and leaves `investment_result = closing - opening`;
2. next-day deposit remains in-period and is subtracted normally.

Apply the same strict lower bound to both effective activities and raw/unsupported activity classification so an opening-day record cannot poison the following interval.

## Rehearse the whole activation in memory

Before productive writes:

1. Open production SQLite read-only.
2. Copy it with SQLite `backup()` into `:memory:`.
3. Execute the actual Preview → cashflow Confirm → recipient-rule activation → period-coverage Confirm path against the memory copy.
4. Call the shipped performance engine for the exact account/scope and period.
5. Assert opening/closing values, zero or expected in-period cashflows, investment result, XIRR, TTWROR, quality, and exact chart-point count.
6. Discard the memory database.

This catches interactions that isolated arithmetic tests miss while preserving production.

## Keep capabilities separate

Historical cashflow confirmation, future recipient-rule activation, and period coverage are separate capabilities and separate audit events:

- Confirming historical contributions materializes only the scope-specific cashflow representations linked to existing bank transactions.
- It does not activate future automation.
- It does not prove broader or global cashflow coverage.
- Coverage is attested only for the exact interval supported by source evidence.
- A future rule activates only after the historical rule fingerprint is confirmed and starts strictly after the confirmed historical window.

A linked performance-cashflow row is not a second household bank transaction. It must reference the existing budget/bank row one-to-one and preserve the three views: household neutral, consolidated wealth neutral, managed-portfolio external contribution.

## Strict API response contracts

A read-only service Preview can work internally yet fail as HTTP 500 when a strict FastAPI/Pydantic response model omits a field returned by the service. For every activation Preview:

- validate the complete service payload with the declared response model in a regression test;
- prefer an endpoint-level test when available;
- keep response models recursively closed, but declare every public provenance/fingerprint field intentionally;
- verify Preview over the deployed HTTP path before any productive Confirm.

Do not mistake successful direct service invocation for a working public API contract.

## Replay evidence

An idempotent replay may return the originally stored `written_cashflows` value rather than `0`. Therefore prove idempotency from database evidence, not response wording alone:

- row-count delta after replay is zero;
- source references remain unique;
- confirmation/audit identity is unchanged;
- no additional financial rows, coverage rows, or recipient-rule activations appear.

## Controlled production sequence

1. Deploy every required semantic/API fix first and verify the imported runtime source path/marker.
2. Create a private SQLite online backup; force mode `0600`, then run integrity and foreign-key checks on source and backup.
3. Capture pre-write counts plus frozen logical hashes for holdings, trades, budget rows, valuation anchors, provider data, and other protected tables.
4. Re-run the exact bank-payment Preview over HTTP and require exact candidate dates, amounts, identity lineage, transfer treatments, no uncertainty, and the expected write count.
5. Confirm once; replay once; verify actual zero replay deltas.
6. Activate the future strong-recipient rule separately; replay and verify.
7. Preview and confirm coverage only for the evidenced interval; replay and verify.
8. Read the performance API and assert engine-derived values—never hardcode them into storage or UI.
9. Compare post-write counts/hashes. Expected mutations should be limited to scope-specific cashflows, exact coverage, and audits; all protected financial-source tables remain unchanged.
10. Render the existing UI before writing frontend code. If the generic performance page already supports source scope plus custom period, use it and verify labels, two-anchor chart, data quality, console, and absence of provider calls during render.

## Stop conditions

Stop before or during activation when:

- opening-day inclusion is not evidenced;
- another contribution/withdrawal exists inside the claimed zero-flow interval;
- a cashflow cannot link one-to-one to its existing bank row;
- the public Preview contract returns validation errors;
- the engine materially disagrees with independent reconciliation;
- replay adds rows;
- protected holdings, trades, anchors, provider data, or unrelated source tables change;
- the UI presents a historical closing anchor as today's value or introduces modelled/interpolated points as confirmed evidence.
