# Observed-price SCD Type 2 (`[15]`)

`sql/price_scd_type2.sql` is a read-only, single-query SCD2 representation of
prices observed in `m5.sell_prices`. It is not a complete corporate price
history and does not claim that a product was available for sale or in stock.

The query first reduces `m5.calendar` to one row per `wm_yr_wk`, with a start
date, end date, and consecutive chronological index. For each `store_id` and
`item_id`, `LAG(sell_price)` detects exact price changes and `LAG(week_index)`
detects missing observed weeks. A cumulative windowed `SUM` assigns a new
segment at the first observation, each price change, and each weekly gap.

Each segment is closed at its final observed week. There is no open-ended date,
sentinel year, forward-fill, missing-price imputation, or use of future data.
An absent source row means “not listed/not observed”; it does not mean a zero
price. NULL, zero, and negative source prices are rejected by the validator
rather than silently converted or omitted. Financial values remain
`DECIMAL(38,24)`.

`sql/price_scd2_temporal_validation.sql` composes the validated SCD2 query and
executes a real SQL temporal join on `store_id`, `item_id`, and
`observation_date BETWEEN valid_from_date AND valid_to_date`. It proves one
match and the exact price for every listed synthetic observation, and zero
matches for every unlisted synthetic week. Its final projection contains only
aggregate counts and booleans. Python separately validates interval shape; it
is not used to claim that the SQL temporal join passed.

The canonical in-memory fixture reproduces the exact approved input contracts:
all 13 ordered `m5.calendar` columns from `date VARCHAR` through `snap_WI`, and
the four ordered `m5.sell_prices` columns with `sell_price DECIMAL(38,24)`.
Name, order, or type drift fails closed.

The point `[15]` evidence remains code-only and is reviewer-approved: both SQL
artifacts pass against the canonical in-memory fixture, and no separate real
point `[15]` attempt was required or performed. The later authorized Data
Foundation closeout executed these same governed SQL paths against a disposable
database reconstructed from the three approved selection-safe Parquet inputs.
That closeout returned only aggregate counts and booleans, cleaned its isolated
workspace, did not materialize protected values, and did not start `[16]` or
`[17]`.
