Skip to content

Commit 3ef1208

Browse files
committed
Search-budget stability methodology audit: cumulative incumbent-preserving design + common Q_ref + multi-part rule
PART 1: the old search_budget_stability ran INDEPENDENT non-nested searches (admissible_near_fit_set(n_candidates=b, seed=fixed) per budget; same seed but different n -> different rng draws -> non-nested pools). PART 2: a larger budget produced a worse best objective (3000->0.111 vs 1500->0.076) purely because the non-nested runs LOST the incumbent (the 3000 run's random pool + Nelder-Mead descent starts landed in a worse basin and did not retain the 1500 run's best theta) -- a numerical exploration artefact, NOT underidentification. New cumulative_near_fit_experiment (partial.py): single rng, incremental NESTED candidate pools (pool(b_k) contains pool(b_{k-1})); each candidate evaluated once under common random numbers and only ADDED (never removed) -> global incumbent retained -> cumulative_best_objective monotone non-increasing ([0.101,0.066,0.065,0.065] for 750/1500/3000/6000); re-evaluating the incumbent is deterministic (delta=0). All budgets compared under ONE common reference minimum Q_ref = min over the whole cumulative experiment, tol_ref = max(1e-4, rel*|Q_ref|) (no moving threshold). Reports both production_near_fit_count (own moving Q_min) and common_threshold_stability_near_fit_count. Replaced the count-growth-only classifier with a documented multi-part convergence rule (cumulative best-objective improvement + common-threshold parameter-support outward expansion + envelope/band/central endpoint movement) -> near_fit_search_stability = INSUFFICIENT_COVERAGE (support still expanding outward at budget 6000, eta lower endpoint 0.80->0.38 -> premature). near_fit_search_stability is reported SEPARATELY from identification_status; unstable search is NOT stated to prove or be an expected signature of underidentification. Production admissible_near_fit_set definition, tolerance rule, SMM moments, rank 4/6, and all ea5b150 prediction semantics unchanged. 8 regression tests; 215 passing. Do not add data/moments/ML. Frozen boundaries preserved.
1 parent ea5b150 commit 3ef1208

6 files changed

Lines changed: 352 additions & 73 deletions

File tree

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![Data refresh](https://github.com/onatozmenn/sold/actions/workflows/kfe-refresh.yml/badge.svg)](https://github.com/onatozmenn/sold/actions/workflows/kfe-refresh.yml)
55
[![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
66
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
7-
[![Tests](https://img.shields.io/badge/tests-207%20passing-brightgreen.svg)](tests/)
7+
[![Tests](https://img.shields.io/badge/tests-215%20passing-brightgreen.svg)](tests/)
88
[![Data](https://img.shields.io/badge/data-TCMB%20%C2%B7%20T%C3%9C%C4%B0K-informational.svg)](#data-sources)
99

1010
> Infer the **realized transaction price** of a Turkish home from its **asking** price — a provenance-aware valuation engine.
@@ -301,7 +301,7 @@ tests/ # offline unit / end-to-end tests
301301
## Testing
302302

303303
```bash
304-
pytest -q # 207 tests, fully offline (no network or API key required)
304+
pytest -q # 215 tests, fully offline (no network or API key required)
305305
```
306306

307307
## Methodology & References
@@ -336,6 +336,7 @@ Negotiation-margin figures from Turkish market reporting: İstanbul ≈ 10%, Ank
336336
- [x] **Econometric terminology correction (near-fit set) + input-conflict diagnostic; core frozen** — the near-minimum SMM criterion level set was renamed `admissible_near_fit_set` (`Θ_A`) and is explicitly **not** described as a formally estimated identified set, a confidence region, or any coverage claim: *the set of economically admissible structural parameter vectors whose SMM criterion lies within the documented near-fit tolerance of the best observed-moment fit* (the tolerance `max(1e-4, rel·|Q_min|)` is a documented numerical/sensitivity rule, **not** a sampling-calibrated cutoff). Local point-identification diagnostics are preserved (`Jacobian rank = 4`, `dim(θ) = 6`) and the reported status is **`STRUCTURALLY_UNDERIDENTIFIED`**. The prediction envelope across `Θ_A` is a **near-fit structural parameter uncertainty envelope** / *structural sensitivity range* — separating *within-θ negotiation uncertainty* from *between-θ near-fit parameter uncertainty* — never a confidence interval or a measured-coverage prediction. A `FUTURE_METHODOLOGY_NOTE` records that a formally calibrated confidence region would need an inference procedure whose criterion cutoff accounts for sampling uncertainty. Added an **input-conflict diagnostic**: `ask_to_fair_value_ratio = asking_price / fair_value` is computed and an explicit `input_conflict` warning is emitted when it falls outside documented configurable bounds (default `[0.5, 2.0]`) — the prediction is **never silently clamped or rejected**; the six economic explanations (`possible_input_error`, `geographic_anchor_mismatch`, `property_characteristic_mismatch`, `distressed_or_nonstandard_sale`, `fractional_or_encumbered_interest`, `strategic_underpricing`) are surfaced as **candidate diagnostic categories only**, never auto-assigned without evidence. Frozen: UYAP+KAP dual-mechanism core, TOKİ external benchmark, `uyap_sale_prob` excluded, the two genuine UYAP + two genuine KAP observations; no ML / weak-supervision / SaleProbability / fourth source / new mechanism. **Econometric core frozen; next is productization + dataset expansion.**
337337
- [x] **Final product surface over the frozen structural engine (honest, demo-ready)** — a polished single-page structural valuation UI (tabs **Değerle / Model Evidence / Method**) and a machine-readable API replace the legacy development form. `POST /structural/valuate` returns `methodology=structural_econometrics`, `identification_status=STRUCTURALLY_UNDERIDENTIFIED`, `coverage_claim=null`, `central_structural_estimate`, `within_theta_negotiation_interval`, `between_theta_near_fit_band`, `structural_sensitivity_range`, `ask_to_fair_value_ratio`, `input_conflict` (+ warning), genuine `2/2/5` UYAP/KAP/TOKİ counts, `jacobian_rank`/`parameter_dimension`/`near_fit_parameter_count` — and **never** a `confidence_interval` or `accuracy` field. The result hierarchy shows the central estimate, within-θ vs between-θ uncertainty, and the sensitivity envelope with the visible statement *"This is not a confidence interval and carries no frequentist coverage claim."* `GET /structural/evidence` reports the genuine public evidence honestly (UYAP conditional-on-completed-sale, KAP corporate-negotiated ≠ ordinary-resale ground truth, TOKİ external = 0 SMM moments) and **does not** display test counts as evidence; `GET /structural/method` explains the mechanism (`TCMB anchor → fair value`, `UYAP/KAP → moments`, `SMM → Θ_A`, `trade iff B≥S`, `P=η·B+(1−η)·S`, `simulation across Θ_A → structural sensitivity range`) with `η` **not** measured from KAP and appraised value **not** the auction reserve; the `[0.5, 2.0]` ask/fair conflict bounds are documented as **configurable product diagnostics, not econometric thresholds**. Input-conflict surfaces an explicit warning with the ratio and the six **candidate** explanation categories (never auto-assigned), and the estimate is **never silently clamped or rejected**. One test-backed correctness fix to the prediction summary: the identification-aware envelope no longer collapses to null when only the single best-fit θ trades zero — it is built from the near-fit configurations that actually trade, while still reporting an honest null when **no** admissible θ trades. Frozen: structural core, TOKİ external, `uyap_sale_prob` excluded, 2 UYAP + 2 KAP; no ML / weak-supervision / SaleProbability / fourth source / new mechanism / auth / billing.
338338
- [x] **Prediction-semantics correctness + Θ_A numerical-robustness audit (pre-expansion)** — traced and fixed the central/within-θ inconsistency: previously the central estimate could be a cross-θ median-of-medians while the within-θ interval came from a different single θ, so the central estimate could fall **outside** its own interval. Now a single **representative trading near-fit configuration** is chosen (the trading θ whose conditional-on-trade median is closest to the cross-θ median, deterministic tie-break) and **both** `central_structural_estimate` and `within_theta_negotiation_interval` are reported from it, so the central estimate lies inside its own interval **by construction** (`central_estimate_definition` / `representative_theta_rule` exposed in metadata). Made conditional-on-trade explicit: `price_estimate_condition=conditional_on_trade`, a permanent statement that the price distribution is computed conditional on `B≥S` (not an unconditional expected sale), primary label *"Central structural estimate, conditional on simulated trade"*, and reconciling counts `near_fit_parameter_count = trading_near_fit_parameter_count + nontrading_near_fit_parameter_count`, `price_envelope_theta_count == trading` (non-trading θ never receive synthetic zero prices; honest null preserved when no θ trades). Corrected the trade field: `trade_probability_band`/`simulated_trade_share_band` is the **Monte-Carlo simulated B≥S share** with `trade_share_calibration=not_empirically_calibrated_to_observed_uyap_no_trade_outcomes` — never a probability of sale / sale likelihood (a simulated share of zero is not proof the population trade probability is zero). Added a reproducible **search-budget stability** study (`GET /structural/stability`, budgets 750/1500/3000, common random numbers, unchanged tolerance/bounds/criterion) with a documented rule → **`near_fit_search_stability = INSUFFICIENT_COVERAGE`**: the finite search finds increasingly many near-fit vectors with budget — the expected numerical signature of a rank-4/6 underidentified region (a large near-flat manifold along ~2 weakly-constrained directions), **not** a code defect. The reproducible sampler was improved (multi-start Nelder-Mead descent to a per-budget `Q_min` + iterative local refinement) — numerical exploration only. Frozen: `STRUCTURALLY_UNDERIDENTIFIED`, rank 4/6, Θ_A/tolerance definition, SMM moments, 2 UYAP + 2 KAP, TOKİ external, `uyap_sale_prob` excluded, TCMB anchor, Nash equation. **Prediction semantics frozen; next is genuine UYAP/KAP evidence expansion.**
339+
- [x] **Search-budget stability methodology audit (cumulative, incumbent-preserving)** — audited why a larger numerical budget had reported a *worse* best objective (`3000` → `0.111` vs `1500` → `0.076`). Root cause: the old study ran **independent, non-nested** searches per budget (same seed, different `n_candidates` → different draws), so a larger budget did **not** retain the smaller budget's best theta — an incumbent-loss / non-nested exploration artefact, **not** underidentification. Redesigned the study as a **cumulative incumbent-preserving experiment** (`cumulative_near_fit_experiment`): nested candidate pools (`pool(bₖ) ⊇ pool(bₖ₋₁)`), every candidate evaluated once under common random numbers, the global incumbent always retained → **`cumulative_best_objective` is monotone non-increasing** (`[0.101, 0.066, 0.065, 0.065]` for `750/1500/3000/6000`), and re-evaluating the incumbent is byte-deterministic (`incumbent_reeval_delta = 0`). All budgets are compared under **one common reference minimum** `Q_ref = min` over the whole cumulative experiment with `tol_ref = max(1e-4, rel·|Q_ref|)` (no moving admission threshold); the table reports both `production_near_fit_count` (own moving `Q_min`) and `common_threshold_stability_near_fit_count`. Replaced the count-growth-only rule with a documented **multi-part** convergence rule (cumulative best-objective improvement, common-threshold parameter-support expansion, envelope/band/central endpoint movement) → **`near_fit_search_stability = INSUFFICIENT_COVERAGE`**: at budget `6000` the common-threshold support is still expanding outward (`eta` lower endpoint `0.80 → 0.38`) so a stability judgment is premature. Crucially, `near_fit_search_stability` is reported **separately** from `identification_status`; unstable numerical search is **not** stated to prove or be an expected signature of underidentification. Frozen: `STRUCTURALLY_UNDERIDENTIFIED`, rank 4/6, Θ_A / tolerance formula, SMM moments, 2 UYAP + 2 KAP, TOKİ external, `uyap_sale_prob` excluded, TCMB anchor, Nash equation, and all `ea5b150` prediction semantics. **Search-approximation layer frozen; next is genuine UYAP/KAP evidence expansion.**
339340
- [ ] **SaleProbability** model (`P(sold ≤ N days)`) trained on collected outcomes
340341
- [ ] Live, ToS-reviewed fetchers for the public label sources
341342
- [ ] Broker-vs-benchmark analytics over an aggregate anonymized dataset

0 commit comments

Comments
 (0)