Skip to content

feat: guarded CRR hybrid diagnostic path (opt-in, ranking-isolated) - #504

Open
gurbeyk wants to merge 31 commits into
tradesdontlie:mainfrom
gurbeyk:phase-2d-hybrid-policy
Open

gurbeyk wants to merge 31 commits into
tradesdontlie:mainfrom
gurbeyk:phase-2d-hybrid-policy

Conversation

@gurbeyk

@gurbeyk gurbeyk commented Sep 4, 2026

Copy link
Copy Markdown

feat: guarded CRR hybrid diagnostic path (opt-in, ranking-isolated)

tedeuxx and others added 30 commits July 22, 2026 11:52
Adds nine readers covering the sections of TradingView's symbol sidebar:
key stats, technicals, forecast, financials, seasonals, news, options,
ETF profile and bond info.

These sections render to canvas, so the DOM holds only axis labels and no
underlying values. Each reader instead issues TradingView's own data request
from page context through the existing evaluateAsync bridge -- same origin,
same session cookies, no new dependency. DOM scraping is kept only for the
forecast consensus gauge, whose rating is encoded as a CSS needle angle that
no endpoint returns.

Two details worth noting:

- The chart's display ticker is the feed venue (BATS:AMZN), which the data
  service answers with a bare null. Readers resolve symbolInfo().pro_name
  (NASDAQ:AMZN) instead, and say so in the error when a caller passes the
  wrong form.
- Seasonality has no endpoint, so it is derived from monthly bars. That means
  briefly switching the chart to 1M and restoring the original resolution --
  the same trade-off getQuote already makes for symbols.

Instruments without a given section (an index has no income statement, a bond
has no options) return an explicit error naming why, not an empty success.

Refs tradesdontlie#379

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113pg14Qw5fjWUs8Vvsp7nJ
Exposes the core readers as data_get_key_stats, data_get_technicals,
data_get_forecast, data_get_financials, data_get_seasonals, data_get_news,
data_get_options, data_get_etf_profile and data_get_bond_info.

Each defaults to the chart's current symbol and takes an optional
exchange-qualified symbol so callers can read any other instrument without
touching the chart.

Refs tradesdontlie#379

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113pg14Qw5fjWUs8Vvsp7nJ
Keeps MCP and CLI at parity: key-stats, technicals, forecast, financials,
seasonals, news, options, etf and bond are all reachable as tv data
subcommands, each taking the same optional symbol flag.

Refs tradesdontlie#379

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113pg14Qw5fjWUs8Vvsp7nJ
Adds a decision-tree section for the symbol data panels, a tool reference
table, and output-size estimates. Notes the two behaviours a caller needs to
know about: listing-venue symbol resolution, and that seasonals is the one
symbol-data tool that touches chart state.

Refs tradesdontlie#379

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113pg14Qw5fjWUs8Vvsp7nJ
Adds options_get_chain: filters the confirmed-working TradingView
options scanner columns (bid/ask/IV/bid-ask IV/Greeks) server-side
in-browser before returning, so only matching contracts cross into
MCP. Explicitly reports available_fields vs unavailable_fields
(volume, open interest, last, bid/ask size, theoretical price,
multiplier are not exposed by this endpoint) rather than inferring
them. data_get_options is untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AVZFFiiJ8tV2hsx89SqMt
Upgrades options_get_chain from /options/scan to /options/scan2,
adding native theoretical_price, root, and currency fields (confirmed
in Phase -1D discovery) and explicit field provenance in the response
(native_fields/derived_fields/unavailable_fields, source_endpoint,
retrieved_at_utc — documented as request time, not an exchange quote
timestamp). Adds a MISSING_THEORETICAL_PRICE quality flag that never
marks a contract untradeable. Extracts the pure input-validation and
per-contract derivation/quality-flag logic into standalone functions
and adds 37 deterministic, network-free unit tests for them. Includes
a design-only note for a future options_get_live_stats enrichment,
not implemented. data_get_options is untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AVZFFiiJ8tV2hsx89SqMt
Adds a pure, TradingView-independent domain layer under
src/core/options/ (strategyTypes, executionModel, strategyEconomics,
strategyCandidates) that turns a normalized option-chain snapshot plus
explicit user constraints into valid directional strategy candidates
(LONG_CALL, LONG_PUT, BULL_CALL_SPREAD, BEAR_PUT_SPREAD, BUY_STOCK,
NO_TRADE) with exact expiration economics and a deterministic payoff
grid. No LLM, no UI, no ranking, no volume/OI dependency — max_loss is
a hard gate, NO_TRADE is never filtered, and contract_multiplier=100
is explicitly marked as an assumption via contract_multiplier_source.

Also extends options_get_chain with total_contracts_available,
chain_completeness, and warnings so callers can detect when the
scanner's 4000-row cap silently truncated a large chain (e.g. SPY) —
data_get_options and options_get_chain's existing filter behavior are
unchanged.

65 new deterministic, network-free tests (textbook fixtures + property/
invariant tests + candidate-generation tests) plus a live NVDA smoke
test in both directions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AVZFFiiJ8tV2hsx89SqMt
Adds LOCAL_GREEK_APPROXIMATION (src/core/options/optionRepricer.js): a
local Taylor-style repricer anchored to TradingView's native
theoretical_price, using delta/gamma/theta/vega under hypothetical
spot/time/IV scenarios. Greek unit conventions were verified against
live NVDA data via a Black-Scholes cross-check before implementation:
theta is already daily $ decay (est. -0.1951 vs observed -0.1932) and
vega is $ per 1 percentage point of IV (est. 0.2175 vs observed
0.2206) — documented in the module header. Falls back to exact
EXPIRATION_INTRINSIC (not the approximation) once days_forward reaches
days_to_expiry, and floors every estimate at intrinsic value and 0.
Generates warnings (never silent confidence) for large spot moves,
large IV changes, large time steps, and near-expiration scenarios.

Adds strategy-level scenario repricing (strategyScenarios.js):
reprices every leg of a Phase 0A candidate, reconciling exactly with
Phase 0A's own expiration economics when days_forward == DTE (unit
tested for LONG_CALL, LONG_PUT, BULL_CALL_SPREAD, BEAR_PUT_SPREAD).
Fees are subtracted exactly once per strategy, never per leg.
BUY_STOCK and NO_TRADE use their own direct formulas with no IV/theta
dependency. Includes buildThreeScenarioSet and buildScenariosFromThesis
as documented convenience helpers (not the only way to build scenarios).

No ranking, no probability-of-profit, no AI — this phase only produces
scenario outcomes. 68 new deterministic, network-free tests (textbook
fixtures, expiry-fallback reconciliation, invariants, and a stress
test asserting warning behavior under extreme moves) plus a live NVDA
scenario smoke test in both directions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AVZFFiiJ8tV2hsx89SqMt
Adds RANKING_MODEL_V1 (src/core/options/strategyRanking.js): a
versioned, absolute (non-percentile) heuristic score built from five
weighted components (base case 35%, downside preservation 25%, upside
participation 20%, breakeven alignment 15%, execution quality 5%),
explicitly labeled as comparative, not a probability or expected
return.

Score and confidence are kept strictly separate per design: confidence
(scenario-model warnings, execution/data quality, chain completeness)
never adjusts score. A candidate can be score=90/confidence=LOW and
both values are reported unmodified. consideration_eligible requires
both a score and a confidence threshold to pass — named explicitly to
avoid implying a recommendation.

NO_TRADE remains a fixed baseline (score=null, always eligible).
BUY_STOCK participates in real scoring as an UNDERLYING_BASELINE.
Optional min_capped_reward_risk hard gate (disabled by default) can
exclude thin spreads outright rather than merely scoring them low.

39 new deterministic, network-free tests including the exact "bad
spread" fixture (risk $465/max profit $35) verified to score below a
superior spread and never rank first, plus a live NVDA test confirming
the key safety property: LARGE_TIME_STEP/NEAR_EXPIRATION warnings
correctly suppress consideration_eligible via LOW confidence even for
mathematically attractive-looking reward:risk candidates.

No AI, no ranking-by-probability, no UI.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AVZFFiiJ8tV2hsx89SqMt
Adds options_analyze_directional, a single read-only MCP tool that
orchestrates the existing deterministic pipeline (options_get_chain ->
strategyCandidates -> strategyScenarios -> strategyRanking) into one
structured analysis packet. Contains no AI/LLM logic and generates no
narrative — the packet is designed to be explained by a downstream
client without recalculating anything itself.

base_target_price is a required, explicit user input — never inferred
from spot, analyst targets, or technicals. Downside/upside scenario
prices default to a documented deterministic helper formula
(scenario_source: DETERMINISTIC_HELPER) when not explicitly supplied.
IV shocks default to 0 with an IV_SCENARIO_NOT_SPECIFIED warning rather
than silently assuming an earnings-style vol move. Thesis direction is
validated against current spot (TARGET_DIRECTION_MISMATCH) before any
chain request is made.

The packet includes per-leg bid/ask/Greeks (no recalculation needed),
a field_provenance map (MARKET_NATIVE/MARKET_DERIVED/ENGINE_CALCULATED/
USER_INPUT/DETERMINISTIC_ASSUMPTION), an ai_contract with explicit
rules for a downstream explainer (never treat score as probability,
never treat consideration_eligible as a recommendation, etc.), and a
deterministic analysis_snapshot_id (sha256-based, not a random UUID)
for traceability.

src/core/options/directionalAnalysis.js supports dependency injection
(mirroring the _deps pattern in chart.js) so its 18 orchestration tests
run fully offline against fixture chain data; live NVDA orchestration
was verified manually. All Phase -1/0A/0B/0C tests continue passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AVZFFiiJ8tV2hsx89SqMt
Codify the Phase 1B-validated explanation behavior as a permanent
CLAUDE.md operating standard so the user no longer has to paste the
long explanation prompt for every directional options request: tool
selection policy, numeric/candidate discipline, score/confidence/
eligibility language rules, NO_TRADE/BUY_STOCK baseline handling, IV
assumption disclosure, and the default Turkish explanation format.

Also corrects volume/OI limitation wording (volume is technically
obtainable via WebSocket but simply unused by this tool, not
categorically unavailable from TradingView), sharpens the tool
description to mark options_analyze_directional as the preferred
high-level entry point, and adds a regression test confirming
analysis_snapshot_id serializes as a string identifier (it already
did, via sha256 hex digest) rather than a JS number.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGqLhe2TW5yk4BKDFHqKb4
Add a pure, provider-independent option pricing benchmark under
src/core/options/pricing/: a Black-Scholes-Merton EUROPEAN reference
pricer (invariant-testing only) and a Cox-Ross-Rubinstein AMERICAN
binomial pricer (CRR_AMERICAN_V1, continuous-dividend-yield V1, price
only, no Greeks). Neither module is wired into
options_analyze_directional, strategyScenarios.js, ranking, or
confidence — LOCAL_GREEK_APPROXIMATION remains production.

Validated via: numerical-safety sweeps, theoretical invariants
(American >= intrinsic, American >= European, Merton's non-dividend
boundary case, monotonicity in volatility, step-count convergence),
early-exercise diagnostics, a convergence/throughput study
(scripts/benchmark-crr-american.mjs), and read-only live calibration
against TradingView's own theoretical_price for PANW (22 contracts,
no dividend) and AAPL (10 contracts, dividend-yield approximation)
via options_get_chain — findings, including a systematic put-side
bias in the PANW sample, are reported as-is per docs/phase-2a-pricer-
benchmark.md rather than tuned away.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGqLhe2TW5yk4BKDFHqKb4
Read-only diagnostic: froze a 52-contract PANW snapshot and compared
TradingView theoretical_price against BLACK_SCHOLES_REFERENCE, a
diagnostic CRR-with-early-exercise-disabled variant, and
CRR_AMERICAN_V1 on identical inputs, plus put-call parity, rate
sensitivity, a best-common-rate grid fit, time-convention, spot-source,
IV/theoPrice self-consistency, bid/ask sanity, and an AAPL cross-check.

Key findings: the original early-exercise-premium hypothesis is
rejected (wrong sign - CRR_American is systematically below, not
above, TradingView's theo for puts); CRR's European mode converges to
independent closed-form BSM to <$0.05 across the sample (no
implementation bug); a best-fit flat rate cuts MAE 3-5x versus the
Phase 2A Treasury-curve proxy but calls and puts fit different rates,
pointing to a secondary un-modeled cost-of-carry factor. Root cause
classified as multiple factors, dominated by a rate/carry convention
mismatch. No independent third-party American pricing benchmark was
available offline - stated rather than fabricated.

No production code changed: crrAmerican.js is untouched, and nothing
is wired into strategyScenarios.js, ranking, confidence, or
options_analyze_directional.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGqLhe2TW5yk4BKDFHqKb4
Phase 2B: a pure market-input layer under src/core/options/
marketInputs/ that separates the discount/funding rate from a
diagnostic effective_carry_yield (deliberately not called
dividend_yield or borrow fee - it's a combined, undecomposed
market-implied carry estimate). Adds Treasury-bill coupon-equivalent
and SOFR-overnight-anchor rate normalization to continuous
compounding with provenance, deterministic matched call/put pair
extraction with quality gates, a synthetic-forward/parity-implied
carry estimator (always labeled as an American-parity approximation),
a second CRR_AMERICAN_V1 joint-carry-fit estimator via bounded 1D
search, a robust cross-strike median/MAD/IQR aggregator, and
documented/tested carry-confidence and estimator-disagreement rules.
26 new tests.

Also relaxes dividend_yield validation in blackScholes.js/
crrAmerican.js from non-negative to signed-finite, since Step 20
requires the pricer to accept a negative effective_carry_yield -
existing non-negative dividend-yield callers are unaffected.

Live calibration (PANW, AAPL, NVDA; scripts/phase2b-carry-
calibration.mjs, docs/phase-2b-market-inputs-carry.md) found the
spec's own 5% default spread threshold yields zero qualifying PANW
pairs at real market spreads, and the calibration/holdout split
correctly caught overfitting on tiny (1-pair) samples where a fitted
carry was worse than q=0. Results are genuinely mixed - the call/put
asymmetry improvement hypothesis held clearly only for the
best-sampled symbol (NVDA). Verdict: promising but needs more
calibration, not yet production-ready.

No production integration: strategyScenarios.js, ranking, confidence,
and options_analyze_directional are unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGqLhe2TW5yk4BKDFHqKb4
Phase 2B.1: src/core/options/marketInputs/jointCarryRegression.js
jointly infers a per-expiration option_implied_discount_rate and
effective_carry_yield from multiple matched call/put strikes (never
pooled across expirations), via weighted-OLS parity regression with
one round of MAD-based outlier rejection, an American early-exercise
correction (CRR_AMERICAN_V1 vs a local CRR-European variant) run as
an iterative fixed point with explicit convergence reporting, broad
diagnostic bounds with ESTIMATOR_BOUND_HIT flagging (never silent
clamping), deterministic calibration/holdout splitting, term-structure
discontinuity flagging, and a frozen Confidence V2 classification.
18 new tests, including the required synthetic recovery fixture
(recovers true r=4%/q=1.5% to within 0.1bp from noiseless synthetic
European pairs) and an American-correction-improves-recovery case.

Live evaluation (PANW across 3 expiries, AAPL, NVDA; reusing the
Phase 2B fixture plus one fresh same-day pull) found none of the
pre-registered Step 15 production-readiness criteria were met by any
symbol/expiry: PANW 48dte's joint-input holdout MAE was worse than
the Treasury-rate/q=0 baseline, NVDA's call/put MAE ratio blew out to
4.61 on a bound-clamped fit, AAPL's improvement fell short of the 15%
bar, and a second independent live snapshot could not be obtained
this session (the market session had not advanced, so true
snapshot-to-snapshot stability - Steps 11/12 - was untestable).
Verdict: NOT RELIABLE for shadow-testing yet; recommend keeping
Treasury-bill rate normalization but treating option-implied carry as
a secondary diagnostic, not a primary production input, pending
genuinely liquid names and multiple real market sessions.

No production integration: strategyScenarios.js, ranking, confidence,
and options_analyze_directional are unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGqLhe2TW5yk4BKDFHqKb4
…CRR shadow scenario engine

(Phase 2C) Adds a production-oriented (but not yet production-wired)
external market input contract under src/core/options/marketInputs/:
productionMarketInputs.js normalizes discount rate (reusing Phase 2B's
validated Treasury-bill conversion), dividend input (5 documented
modes, never silently converting unavailable to zero), and borrow
input (never silently defaulting to 0); dividendProviders.js and
borrowProviders.js implement the provider interfaces via dependency
injection, with a TradingView key-stats dividend adapter and an
IBKR-shaped borrow adapter interface that stores no credentials and is
NOT_CONNECTED by default (no live securities-lending source exists in
this environment).

Adds a side-by-side CRR_AMERICAN_V1 shadow pricing pathway
(pricing/crrShadowRepricer.js, marketInputs/crrShadowScenario.js) that
mirrors optionRepricer.js/strategyScenarios.js's shapes and aggregation
math exactly without modifying either file, so shadow-priced
candidates feed directly into the unmodified rankStrategyCandidates
for a "shadow ranking" comparison. Documents and tests the carry sign
convention (dividend + borrow additive, same directional effect,
verified rather than assumed). 30 new tests, including exact
expiration reconciliation for all four required strategy types.

Live read-only comparison (NVDA/AAPL/PANW, scripts/phase2c-crr-shadow-
live.mjs) found: borrow data is unavailable in this environment, so
every live market-input record capped at PARTIAL_EXTERNAL_INPUTS with
LOW-MEDIUM confidence; model disagreement concentrates where
LOCAL_GREEK_APPROXIMATION already carries a warning (9.6-16.8% mean vs
0.00% unwarned, thin sample); and shadow ranking shows real
instability, especially NVDA (top-5 overlap only 1/5, one candidate
moving 33 ranks). Verdict: promising but market inputs incomplete, not
yet a production-migration candidate.

No production pricing switch: strategyScenarios.js, strategyRanking.js,
directionalAnalysis.js, and options_analyze_directional output
semantics are all unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGqLhe2TW5yk4BKDFHqKb4
Phase 2C.1: a read-only IBKR Client Portal Web API adapter under
src/providers/ibkr/ (clientPortalClient.js: HTTP boundary using the
current /iserver/marketdata/snapshot route, not the deprecated
/md/regsnapshot; ibkrMarketInputsProvider.js: pure parsers for Fee
Rate/Shortable/Dividends/market-data-availability fields plus
connection-status probing, conid resolution, and bounded snapshot
preflight retry). No credentials are stored; base URL is configurable
via IBKR_API_BASE_URL (never hard-coded to port 5000); the adapter
never throws on missing/unauthenticated connections, returning
CONNECTED/AUTH_REQUIRED/UNAVAILABLE so pricing code can continue with
explicit missing-borrow handling. Adds provider precedence
(marketInputPrecedence.js: IBKR forward dividend -> TradingView
trailing yield -> documented zero -> unavailable; IBKR Fee Rate ->
unavailable, explicitly never Phase 2B/2B.1's option-implied carry)
and a distinct shadow-only market-input confidence classification. 38
new tests, all against frozen fixtures/fakes - no live IBKR auth
required.

Live probing found no reachable IBKR Client Portal Gateway in this
environment (connection refused on :5000 and :5001), so the graduated
5/15/30-day shadow re-validation (scripts/phase2c1-graduated-shadow-
live.mjs) ran with IBKR inputs UNAVAILABLE and is labeled
OFF_HOURS_DIAGNOSTIC (run on a closed-market Sunday). Findings:
disagreement rises monotonically with horizon as hypothesized (5-day
median 0.5-1.1%, comfortably under the 10%/15% success thresholds);
warned candidates show 3-6x higher disagreement than unwarned ones
(a much better-supported result than Phase 2C's thin sample); a
borrow-fee ablation shows adding borrow barely moves rankings (5/5
top-5 overlap for all three symbols); and critically, NVDA's Phase 2C
ranking instability did NOT reproduce under this phase's symmetric
scenario set (5/5 overlap, borrow contributes almost nothing) -
suggesting Phase 2C's severe instability was driven by the specific
scenario percentages used, not the pricing model or missing borrow
data, an open question this phase surfaces but does not fully resolve.

No production changes: pricing model, ranking confidence, and
options_analyze_directional semantics are unchanged; no order/account
functionality was added.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGqLhe2TW5yk4BKDFHqKb4
Codex ran the Phase 2C.2 live acceptance test during an active U.S.
market session (2026-09-02, ~14:00 ET) using the existing CRR shadow
pipeline and IBKR adapter from Phases 2C/2C.1 - no code changes were
needed or made. Result: PARTIAL PASS. TradingView live data and CRR
shadow execution both passed cleanly; IBKR remained unavailable (no
reachable gateway), so market inputs stayed PARTIAL_EXTERNAL_INPUTS
throughout.

This documents that result against the Phase 2C.2 report template and
Step 23's pre-registered pass conditions: 5-day disagreement and
warning-correlation evidence both pass comfortably and with the
largest sample sizes yet, but AAPL showed a real, unexplained 2/5
top-5 ranking instability under the symmetric STRESS_30D set - and
critically, the symbol/scenario-set pairing that showed instability
has now flipped between sessions (NVDA under thesis-shifted in Phase
2C, AAPL under symmetric today), undermining the earlier hypothesis
that it was a fixed, explainable scenario-sensitivity property. Root-
cause decomposition (Steps 9/11) could not be completed because
per-candidate P&L/component-score detail wasn't captured in this
run's data - flagged as the top priority for the next live run.

Verdict: B) CRR VALID BUT MORE LIVE EVIDENCE REQUIRED, not ready for
migration. Evidence archived at docs/fixtures/phase2c2-live-
acceptance-20260902/ (summary .md + raw .json as collected).

No production changes: pricing model, ranking, and confidence
thresholds are unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGqLhe2TW5yk4BKDFHqKb4
Phase 2D.3: adds buildTradingViewCrrShadowMarketInputs() (src/core/
options/marketInputs/tradingViewCrrShadowMarketInputs.js), a real
default provider for the Phase 2D.2 guarded
include_crr_hybrid_diagnostics hook. Composes discount (Treasury
resolveDiscountRate against a frozen, explicitly-labeled fallback bill
table), dividend (TradingView key-stats trailing yield via the Phase
2C.1 precedence chain, with an exact-0% yield treated as documented
ZERO_DIVIDEND_CONFIRMED - the established PANW pattern, applied
generically), and borrow (always BORROW_DATA_UNAVAILABLE, since no
IBKR session exists - the account isn't funded/active). Every record
is therefore PARTIAL_EXTERNAL_INPUTS by construction, never
FULL_EXTERNAL_INPUTS.

directionalAnalysis.js now defaults deps.buildCrrShadowMarketInputs to
this provider via the same `deps.x ?? _x` pattern already used for
getOptionChain/getKeyStats, so include_crr_hybrid_diagnostics works
without manual wiring. Tests can still force the "no provider" path
with a non-nullish, non-function override (false), since `??` only
substitutes on null/undefined.

5 new tests in directional_analysis.test.js cover: default AVAILABLE
with PARTIAL_EXTERNAL_INPUTS + borrow unavailable, zero vs trailing
dividend mode selection, safe (non-fabricated) handling when dividend
data is missing, and byte-identical ranking/score/confidence/
eligibility with diagnostics on vs off. Full relevant suite (142
tests across 7 files) and directional_analysis.test.js (27 tests)
both pass; lint clean (0 errors, only pre-existing unrelated
warnings).

No production changes: ranking, scoring, confidence, eligibility,
recommendations, and local-Greek pricing are all unchanged - this
only makes an existing diagnostic-only field easier to populate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UGqLhe2TW5yk4BKDFHqKb4
Validates options_analyze_directional with include_crr_hybrid_diagnostics
through the live MCP tool path (real CDP connection to TradingView
Desktop) for NASDAQ:NVDA, NASDAQ:AAPL, NASDAQ:PANW. Confirms diagnostics
stay DIAGNOSTIC_ONLY_NO_RANKING_CHANGE, market input modes/confidence
vary sensibly per symbol, and eligibility gating behaves per the Options
Copilot standard. No bugs found; no code changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EL2wsSZakDc4bFWysqWPc9
Validates options_analyze_directional with direction: bearish and
include_crr_hybrid_diagnostics through the live MCP tool path for
NASDAQ:NVDA, NASDAQ:AAPL, NASDAQ:PANW. Confirms diagnostics stay
AVAILABLE / DIAGNOSTIC_ONLY_NO_RANKING_CHANGE, market inputs stay
PARTIAL_EXTERNAL_INPUTS with borrow always unavailable, local-Greek
ranking (RANKING_MODEL_V1) is untouched, NO_TRADE baseline is preserved
correctly, and the bearish put-side candidate universe (BEAR_PUT_SPREAD)
is populated and internally differentiated. No bugs found; no code
changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EL2wsSZakDc4bFWysqWPc9
Closes the coverage gap left by Phase 2D.5, where all three bearish test
symbols hit NO_TRADE_BASELINE_ONLY. Root-caused the block to the
LARGE_TIME_STEP scenario warning (structural at horizon_days=30 for any
contract with daysToExpiry<60), then found a live MCP tool run reaching
TRADE_CANDIDATES_AVAILABLE for NASDAQ:NVDA, NASDAQ:AAPL, and
NASDAQ:PANW by widening min_dte/max_dte to 60/90 -- a parameter choice,
not a code change, with minimum_score_for_consideration and
minimum_confidence_for_consideration left at production defaults.
Diagnostics stayed AVAILABLE / DIAGNOSTIC_ONLY_NO_RANKING_CHANGE,
market inputs stayed PARTIAL_EXTERNAL_INPUTS with borrow unavailable,
and ranking stayed on RANKING_MODEL_V1 throughout. AAPL additionally
surfaced LONG_PUT as an eligible top candidate. No bugs found; no code
changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EL2wsSZakDc4bFWysqWPc9
Consolidates Phase 2D through 2D.6 into a single decision checkpoint:
guarded hybrid CRR diagnostics are accepted as a shipped, opt-in,
ranking-isolated feature; full CRR production migration, a production
ranking switch, and IBKR/FULL_EXTERNAL_INPUTS dependency are all
explicitly rejected for now. Documents what was and wasn't proven,
per-phase summaries with commit/evidence references, remaining gaps,
and a go/no-go table. Recommends Phase 2E.1 (release gate / contract
stabilization) as the next step, not further migration work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EL2wsSZakDc4bFWysqWPc9
Freezes the public shape of diagnostics.crr_hybrid_policy per the Phase
2E.0 migration decision (guarded diagnostics stay, no CRR migration).
Adds 7 type/shape-precise tests to tests/directional_analysis.test.js
covering all three statuses (NOT_REQUESTED/UNAVAILABLE/AVAILABLE),
market_inputs[] and candidates[] field shapes, summary consistency, the
FULL_EXTERNAL_INPUTS ceiling, and ranking non-interference. Adds a
standalone user/agent-facing contract doc
(docs/crr-hybrid-diagnostic-contract.md) stating diagnostics are opt-in,
evidence-only, and never a trade recommendation. No production code
changed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EL2wsSZakDc4bFWysqWPc9
Packages Phase 2D through 2E.1's guarded CRR hybrid diagnostic work into
a merge-ready handoff: branch/commit range, what ships vs. what
explicitly doesn't, the frozen public contract, user/agent safety
rules, a four-level validation evidence summary (unit tests, live
script acceptance, live real-MCP-tool bullish/bearish coverage), the
Phase 2E.0 migration decision, known caveats, a merge/PR checklist, a
rollback/safety note, and a suggested PR title/description. No code
changes; packaging only.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EL2wsSZakDc4bFWysqWPc9
Fixes a self-referential staleness in the Phase 2E.2 handoff doc: it
listed its own not-yet-existing commit as "Head commit" and asserted an
exact commit-ahead count that changes as soon as the doc itself (and
this polish) land. Points readers to main..phase-2d-hybrid-policy as
the authoritative source for the live count/hash instead. No content
about what ships or the validation evidence changed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EL2wsSZakDc4bFWysqWPc9
@gurbeyk

gurbeyk commented Sep 4, 2026

Copy link
Copy Markdown
Author

feat: guarded CRR hybrid diagnostic path (opt-in, ranking-isolated)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants