sat_factor = 1 + ((sold_pct-50)/100)*0.30 was computed in 09_macro_and_trend.py,
written to district_economics.sat_factor, and fetched in server.py and 10_score_v2.py
— but never multiplied into any score. The live market sub-score uses a separate
sat_score = min(100, sold_pct*100/70) directly, so sat_factor was dead code that
would double-count absorption if ever wired in.
- 09_macro_and_trend.py: remove sat_factor computation, ALTER TABLE column, UPDATE
binding, and debug print column
- 10_score_v2.py: remove sat_factor from SELECT and unpacking
- server.py: remove sat_factor variable assignment and from macro_factors response
- static/index.html: remove sat_factor documentation row
- data/sql/162_drop_district_economics_sat_factor.sql: DROP COLUMN IF EXISTS
When v_prior == 0 and v_rec > 0, the old code unconditionally assigned
trend_ratio = 2.0, producing an artificial 2x jump even for districts
with negligible recent velocity.
New formula:
ratio = 1.0 + min(1.0, v_rec / _REF_VELOCITY) * (_TREND_CAP_VPRIOR_ZERO - 1.0)
Where:
_REF_VELOCITY = 10.0 (monthly flats/corpus — EKB "well-performing" benchmark)
_TREND_CAP_VPRIOR_ZERO = 1.5 (max ratio for the v_prior==0 case)
Tiny v_rec (e.g. 1 flat/month) → ratio ≈ 1.05 (near neutral)
Large v_rec (≥ 10 flat/month) → ratio → 1.5 (capped, below old hard 2.0)
v_prior > 0 branch is unchanged.
Also fixes pre-existing ruff violations in the same file (E401 multi-import,
E701 inline colon, E722 bare except, F401 unused import) so ruff check passes clean.