@@ -718,6 +718,92 @@ def test_vrp_returns_full_payload(fa):
718718 assert "vix" in r ["macro" ]
719719
720720
721+ def test_vrp_every_field_declared_in_poco_must_be_referenced (fa ):
722+ """Every leaf field declared in VrpResponse must be referenced.
723+
724+ 100% field-coverage discipline (mirrors the ExposureSummary contract).
725+ Live-specific:
726+ - macro.fed_funds is present (live-only field).
727+ - macro.hy_spread may currently be null (data-pipeline gap).
728+ """
729+ r = fa .vrp ("SPY" )
730+
731+ # ── top-level scalars ──
732+ assert r ["symbol" ] == "SPY"
733+ assert isinstance (r ["underlying_price" ], (int , float )) and r ["underlying_price" ] > 0
734+ assert isinstance (r ["as_of" ], str ) and r ["as_of" ]
735+ assert isinstance (r ["market_open" ], bool )
736+ assert isinstance (r ["variance_risk_premium" ], (int , float ))
737+ assert isinstance (r ["convexity_premium" ], (int , float ))
738+ assert isinstance (r ["fair_vol" ], (int , float ))
739+ assert isinstance (r ["dealer_flow_risk" ], (int , float ))
740+ assert isinstance (r ["net_harvest_score" ], (int , float ))
741+ assert isinstance (r ["warnings" ], list )
742+ # Customer traps: these MUST NOT be top-level
743+ assert "z_score" not in r
744+ assert "percentile" not in r
745+ assert "atm_iv" not in r
746+ assert "net_gex" not in r
747+ assert "put_vrp" not in r and "call_vrp" not in r
748+ assert "harvest_score" not in r # under gex_conditioned
749+
750+ # ── vrp.* core block ──
751+ core = r ["vrp" ]
752+ for k in ("atm_iv" , "rv_5d" , "rv_10d" , "rv_20d" , "rv_30d" ,
753+ "vrp_5d" , "vrp_10d" , "vrp_20d" , "vrp_30d" ):
754+ assert isinstance (core [k ], (int , float )), f"vrp.{ k } "
755+ assert isinstance (core ["z_score" ], (int , float ))
756+ assert isinstance (core ["percentile" ], int ) and 0 <= core ["percentile" ] <= 100
757+ assert isinstance (core ["history_days" ], int )
758+
759+ # ── directional ──
760+ d = r ["directional" ]
761+ for k in ("put_wing_iv_25d" , "call_wing_iv_25d" ,
762+ "downside_rv_20d" , "upside_rv_20d" ,
763+ "downside_vrp" , "upside_vrp" ):
764+ assert isinstance (d [k ], (int , float )), f"directional.{ k } "
765+
766+ # ── term_vrp[] ──
767+ term = r ["term_vrp" ]
768+ assert isinstance (term , list ) and len (term ) > 0
769+ first = term [0 ]
770+ assert isinstance (first ["dte" ], int )
771+ for k in ("iv" , "rv" , "vrp" ):
772+ assert isinstance (first [k ], (int , float )), f"term_vrp[0].{ k } "
773+
774+ # ── gex_conditioned ──
775+ gex_c = r ["gex_conditioned" ]
776+ assert isinstance (gex_c ["regime" ], str )
777+ assert isinstance (gex_c ["harvest_score" ], (int , float ))
778+ assert isinstance (gex_c ["interpretation" ], str )
779+
780+ # ── vanna_conditioned ──
781+ vanna_c = r ["vanna_conditioned" ]
782+ assert isinstance (vanna_c ["outlook" ], str )
783+ assert isinstance (vanna_c ["interpretation" ], str )
784+
785+ # ── regime (net_gex lives HERE) ──
786+ reg = r ["regime" ]
787+ assert isinstance (reg ["gamma" ], str )
788+ assert isinstance (reg ["vrp_regime" ], str )
789+ assert isinstance (reg ["net_gex" ], (int , float ))
790+ assert isinstance (reg ["gamma_flip" ], (int , float ))
791+
792+ # ── strategy_scores ──
793+ ss = r ["strategy_scores" ]
794+ for k in ("short_put_spread" , "short_strangle" , "iron_condor" , "calendar_spread" ):
795+ assert isinstance (ss [k ], int ) and 0 <= ss [k ] <= 100 , f"strategy_scores.{ k } "
796+
797+ # ── macro (live-specific includes fed_funds) ──
798+ m = r ["macro" ]
799+ for k in ("vix" , "vix_3m" , "vix_term_slope" , "dgs10" ):
800+ assert isinstance (m [k ], (int , float )), f"macro.{ k } "
801+ # hy_spread present but may be null on live currently
802+ assert "hy_spread" in m and (m ["hy_spread" ] is None or isinstance (m ["hy_spread" ], (int , float )))
803+ # fed_funds is the live-only macro field
804+ assert "fed_funds" in m and isinstance (m ["fed_funds" ], (int , float ))
805+
806+
721807# Issue #1 — Nested response structures. Customer accessed
722808# response["z_score"] directly and got None. The field lives at
723809# response["vrp"]["z_score"]. Tests assert the documented nesting.
0 commit comments