From: Jérôme Benoit Date: Fri, 2 Oct 2026 18:43:29 +0000 (+0200) Subject: fix(reforcexy): close persisted reward and QA boundary findings X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=c329c2fb3afe3ef4ac2861562c58025d338de2ae;p=freqai-strategies.git fix(reforcexy): close persisted reward and QA boundary findings --- diff --git a/README.md b/README.md index fd20675..e8f16cf 100644 --- a/README.md +++ b/README.md @@ -395,11 +395,13 @@ Freqtrade's `proposed_leverage` before clamping. Continual learning trains an independent copy of the deployed policy with its fitted feature pipeline. DQN/QRDQN deployments each persist their replay buffer; it is loaded only when continual training starts. Missing or incompatible replay -data prevents continuation but does not prevent inference. Reset trained models -or use a new `freqai.identifier` to migrate incompatible artifacts, including -deployments without the chronological training marker. Training disables -`shuffle_after_split`. HPO studies and saved best parameters are reused only -when their objective identity matches. +data prevents continuation but does not prevent inference. The deployment +generation covers frozen feature coordinates and PBRS reward semantics. Older +generations, including `chronological-frozen-pipelines-v2`, remain usable for +inference but cannot continue training. Reset trained models or use a new +`freqai.identifier` to migrate. Training disables `shuffle_after_split`. HPO +studies and saved best parameters are reused only when their objective identity +matches. Backtests continue only from a saved policy whose training cutoff precedes the current window's end and its last available candle boundary. A later @@ -424,6 +426,9 @@ Rows with an invalid `date_pred` are discarded with a per-pair warning and the discarded-row count; valid duplicates retain the same precedence. See the model docstrings for continuation, HPO and statistics details. +An expired model closes only open positions for the current pair, using each +position's own side; positions for other pairs cannot generate its exit signals. + With `hold_potential_enabled=true`, ReforceXY enables `add_state_info` before constructing environments so training and inference use the same observations. Freqtrade does not support these state observations in backtesting; disable hold @@ -465,7 +470,8 @@ Non-positive or non-finite equity produces NaN diagnostics rather than a zero return. These diagnostics do not change the training reward or realized capital. Rewards combine the fill-time base components with a potential-based shaping delta over the returned next observation. Termination liquidates any remaining -position once and clears the terminal potential. `get_env_history()` returns one +position once and sets terminal shaping to `-prev_potential`, even for tiny +nonzero potentials. `get_env_history()` returns one metrics/price row per transition. Its `execution_tick` is the transition/action/fill key before the tick increment; its `tick` is the returned post-increment price and observation row (normally `execution_tick + 1`). Exit-efficiency extrema include @@ -483,11 +489,13 @@ effective additives are disabled. It is a conservative configuration check, not a guarantee about fitted policies: theoretical invariance also requires an observable state potential, the learner's discount, and appropriate boundaries. -An absent learner `gamma` uses the canonical discount. An effective `gamma: null` -is rejected before constructing or replacing environments. Validation follows -HPO overrides and the resumed learner's gamma, so a valid higher-priority value -can supersede a null base value. Learner and environment receive the same -effective discount. +An absent configured `gamma` uses the canonical discount. The effective discount +must be a finite Python/NumPy integer or floating scalar in `[0, 1]`, normalized +to a Python float. Null, booleans, strings, complex values and arrays are rejected +before constructing or replacing environments. Validation follows HPO overrides +and the resumed learner's gamma, so a valid higher-priority value can supersede +an invalid base value. A persisted learner with missing or invalid gamma cannot +continue training. Learner and environment use the same effective discount. The corrected reward objective invalidates persisted HPO studies and best parameters from the previous objective identity; incompatible studies are reset and stale best-parameter payloads are ignored rather than warm-started. @@ -523,8 +531,9 @@ Each strategy QA matrix entry runs its type check and canonical coverage suite. ReforceXY additionally runs once with `FREQAI_QA_SHUFFLE_SEED=1`. This permutes methods within test classes, not module or class order. `QaTestCase` restores the action-mask cache and the Python, NumPy and CPU Torch RNG states before and after -each test. Tests must isolate other mutable state themselves; the alternate order -does not prove the absence of all global-state leaks. +each test. Lifecycle probes cover successful cases, body failures and setup or +teardown errors. Tests must isolate other mutable state themselves; the alternate +order does not prove the absence of all global-state leaks. The ReforceXY gate measures **only `ReforceXY/user_data`**, with branch coverage and non-imported namespace files included. Tests, the analytical package and diff --git a/ReforceXY/.basedpyright/diagnostics.json b/ReforceXY/.basedpyright/diagnostics.json index e0c2a4f..e69d425 100644 --- a/ReforceXY/.basedpyright/diagnostics.json +++ b/ReforceXY/.basedpyright/diagnostics.json @@ -203,923 +203,883 @@ }, { "endCharacter": 22, - "endLine": 1017, + "endLine": 1025, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Cannot assign to attribute \"train_env\" for class \"ReforceXY*\"\n  Expression of type \"VecEnv\" cannot be assigned to attribute \"train_env\" of class \"ReforceXY\"\n    Type \"VecEnv\" is not assignable to type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\"\n      \"VecEnv\" is not assignable to \"VecMonitor\"\n      \"VecEnv\" is not assignable to \"SubprocVecEnv\"\n      \"VecEnv\" is not assignable to \"Env[Unknown, Unknown]\"", "rule": "reportAttributeAccessIssue", "severity": "error", "startCharacter": 13, - "startLine": 1017 + "startLine": 1025 }, { "endCharacter": 37, - "endLine": 1017, + "endLine": 1025, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Cannot assign to attribute \"eval_env\" for class \"ReforceXY*\"\n  Expression of type \"VecEnv | None\" cannot be assigned to attribute \"eval_env\" of class \"ReforceXY\"\n    Type \"VecEnv | None\" is not assignable to type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\"\n      Type \"VecEnv\" is not assignable to type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\"\n        \"VecEnv\" is not assignable to \"VecMonitor\"\n        \"VecEnv\" is not assignable to \"SubprocVecEnv\"\n        \"VecEnv\" is not assignable to \"Env[Unknown, Unknown]\"", "rule": "reportAttributeAccessIssue", "severity": "error", "startCharacter": 29, - "startLine": 1017 + "startLine": 1025 }, { "endCharacter": 24, - "endLine": 1276, + "endLine": 1284, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"VecEnv\" cannot be assigned to parameter \"eval_env\" of type \"BaseEnvironment\" in function \"__init__\"\n  \"VecEnv\" is not assignable to \"BaseEnvironment\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 16, - "startLine": 1276 + "startLine": 1284 }, { "endCharacter": 38, - "endLine": 1504, + "endLine": 1517, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"obj\" of type \"Sized\" in function \"len\"\n  Type \"Any | None\" is not assignable to type \"Sized\"\n    \"None\" is incompatible with protocol \"Sized\"\n      \"__len__\" is not present", "rule": "reportArgumentType", "severity": "error", "startCharacter": 30, - "startLine": 1504 + "startLine": 1517 }, { "endCharacter": 36, - "endLine": 1508, + "endLine": 1521, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"obj\" of type \"Sized\" in function \"len\"\n  Type \"Any | None\" is not assignable to type \"Sized\"\n    \"None\" is incompatible with protocol \"Sized\"\n      \"__len__\" is not present", "rule": "reportArgumentType", "severity": "error", "startCharacter": 29, - "startLine": 1508 + "startLine": 1521 }, { "endCharacter": 80, - "endLine": 1511, + "endLine": 1524, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"steps_to_days\"\n  Type \"Any | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 52, - "startLine": 1511 + "startLine": 1524 }, { "endCharacter": 78, - "endLine": 1512, + "endLine": 1525, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"steps_to_days\"\n  Type \"Any | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 50, - "startLine": 1512 + "startLine": 1525 }, { "endCharacter": 80, - "endLine": 1513, + "endLine": 1526, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"steps_to_days\"\n  Type \"Any | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 52, - "startLine": 1513 + "startLine": 1526 }, { "endCharacter": 56, - "endLine": 1599, + "endLine": 1610, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\" cannot be assigned to parameter \"eval_env\" of type \"VecEnv | None\" in function \"get_callbacks\"\n  Type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\" is not assignable to type \"VecEnv | None\"\n    Type \"Env[Unknown, Unknown]\" is not assignable to type \"VecEnv | None\"\n      \"Env[Unknown, Unknown]\" is not assignable to \"VecEnv\"\n      \"Env[Unknown, Unknown]\" is not assignable to \"None\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 43, - "startLine": 1599 + "startLine": 1610 }, { "endCharacter": 84, - "endLine": 1619, + "endLine": 1630, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"float | list[float]\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | list[float]\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"list[float]\" is not assignable to type \"ConvertibleToFloat\"\n      \"list[float]\" is not assignable to \"str\"\n      \"list[float]\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"list[float]\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"list[float]\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 67, - "startLine": 1619 + "startLine": 1630 }, { "endCharacter": 84, - "endLine": 1619, + "endLine": 1630, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"float | list[float]\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | list[float]\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"list[float]\" is not assignable to type \"ConvertibleToFloat\"\n      \"list[float]\" is not assignable to \"str\"\n      \"list[float]\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"list[float]\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"list[float]\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 67, - "startLine": 1619 + "startLine": 1630 }, { "endCharacter": 44, - "endLine": 2693, + "endLine": 2704, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "\"best_trial_params\" is possibly unbound", "rule": "reportPossiblyUnboundVariable", "severity": "error", "startCharacter": 27, - "startLine": 2693 + "startLine": 2704 }, { "endCharacter": 12, - "endLine": 2713, + "endLine": 2724, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Parameter declaration \"seed\" is obscured by a declaration of the same name", "rule": "reportRedeclaration", "severity": "error", "startCharacter": 8, - "startLine": 2713 + "startLine": 2724 }, { "endCharacter": 16, - "endLine": 2714, + "endLine": 2725, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Parameter declaration \"env_info\" is obscured by a declaration of the same name", "rule": "reportRedeclaration", "severity": "error", "startCharacter": 8, - "startLine": 2714 + "startLine": 2725 }, { "endCharacter": 51, - "endLine": 2757, + "endLine": 2768, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"list[() -> BaseEnvironment]\" cannot be assigned to parameter \"env_fns\" of type \"list[() -> Env[Unknown, Unknown]]\" in function \"__init__\"\n  \"list[() -> BaseEnvironment]\" is not assignable to \"list[() -> Env[Unknown, Unknown]]\"\n    Type parameter \"_T@list\" is invariant, but \"() -> BaseEnvironment\" is not the same as \"() -> Env[Unknown, Unknown]\"\n    Consider switching from \"list\" to \"Sequence\" which is covariant", "rule": "reportArgumentType", "severity": "error", "startCharacter": 42, - "startLine": 2757 + "startLine": 2768 }, { "endCharacter": 53, - "endLine": 2763, + "endLine": 2774, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"list[() -> BaseEnvironment]\" cannot be assigned to parameter \"env_fns\" of type \"list[() -> Env[Unknown, Unknown]]\" in function \"__init__\"\n  \"list[() -> BaseEnvironment]\" is not assignable to \"list[() -> Env[Unknown, Unknown]]\"\n    Type parameter \"_T@list\" is invariant, but \"() -> BaseEnvironment\" is not the same as \"() -> Env[Unknown, Unknown]\"\n    Consider switching from \"list\" to \"Sequence\" which is covariant", "rule": "reportArgumentType", "severity": "error", "startCharacter": 45, - "startLine": 2763 + "startLine": 2774 }, { "endCharacter": 22, - "endLine": 2826, + "endLine": 2837, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Operator \"*\" not supported for \"None\"", "rule": "reportOptionalOperand", "severity": "error", "startCharacter": 15, - "startLine": 2826 + "startLine": 2837 }, { "endCharacter": 96, - "endLine": 2828, + "endLine": 2839, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Operator \"*\" not supported for \"None\"", "rule": "reportOptionalOperand", "severity": "error", "startCharacter": 89, - "startLine": 2828 + "startLine": 2839 }, { "endCharacter": 23, - "endLine": 2831, + "endLine": 2842, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Operator \"*\" not supported for \"None\"", "rule": "reportOptionalOperand", "severity": "error", "startCharacter": 16, - "startLine": 2831 + "startLine": 2842 }, { "endCharacter": 98, - "endLine": 2833, + "endLine": 2844, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Operator \"*\" not supported for \"None\"", "rule": "reportOptionalOperand", "severity": "error", "startCharacter": 91, - "startLine": 2833 + "startLine": 2844 }, { "endCharacter": 44, - "endLine": 2845, + "endLine": 2856, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Operator \"*\" not supported for types \"Any | None\" and \"Any | int | None\"\n  Operator \"*\" not supported for types \"None\" and \"None\"\n  Operator \"*\" not supported for types \"None\" and \"int\"", "rule": "reportOperatorIssue", "severity": "error", "startCharacter": 15, - "startLine": 2845 + "startLine": 2856 }, { "endCharacter": 133, - "endLine": 2847, + "endLine": 2858, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Operator \"*\" not supported for types \"Any | None\" and \"Any | int | None\"\n  Operator \"*\" not supported for types \"None\" and \"None\"\n  Operator \"*\" not supported for types \"None\" and \"int\"", "rule": "reportOperatorIssue", "severity": "error", "startCharacter": 106, - "startLine": 2847 + "startLine": 2858 }, { "endCharacter": 30, - "endLine": 2850, + "endLine": 2861, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Operator \">\" not supported for \"None\"", "rule": "reportOptionalOperand", "severity": "error", "startCharacter": 15, - "startLine": 2850 + "startLine": 2861 }, { "endCharacter": 54, - "endLine": 2916, + "endLine": 2927, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "\"is_pruned\" is not a known attribute of \"None\"", "rule": "reportOptionalMemberAccess", "severity": "error", "startCharacter": 45, - "startLine": 2916 + "startLine": 2927 }, { "endCharacter": 67, - "endLine": 2919, + "endLine": 2930, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "\"use_masking\" is not a known attribute of \"None\"", "rule": "reportOptionalMemberAccess", "severity": "error", "startCharacter": 56, - "startLine": 2919 + "startLine": 2930 }, { "endCharacter": 60, - "endLine": 2927, + "endLine": 2938, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "\"update_best_reward\" is not a known attribute of \"None\"", "rule": "reportOptionalMemberAccess", "severity": "error", "startCharacter": 42, - "startLine": 2927 + "startLine": 2938 }, { "endCharacter": 84, - "endLine": 2927, + "endLine": 2938, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"float | list[float]\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | list[float]\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"list[float]\" is not assignable to type \"ConvertibleToFloat\"\n      \"list[float]\" is not assignable to \"str\"\n      \"list[float]\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"list[float]\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"list[float]\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 67, - "startLine": 2927 + "startLine": 2938 }, { "endCharacter": 84, - "endLine": 2927, + "endLine": 2938, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"float | list[float]\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | list[float]\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"list[float]\" is not assignable to type \"ConvertibleToFloat\"\n      \"list[float]\" is not assignable to \"str\"\n      \"list[float]\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"list[float]\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"list[float]\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 67, - "startLine": 2927 + "startLine": 2938 }, { "endCharacter": 46, - "endLine": 2981, + "endLine": 2992, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "\"is_pruned\" is not a known attribute of \"None\"", "rule": "reportOptionalMemberAccess", "severity": "error", "startCharacter": 37, - "startLine": 2981 + "startLine": 2992 }, { "endCharacter": 57, - "endLine": 2984, + "endLine": 2995, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "\"best_mean_reward\" is not a known attribute of \"None\"", "rule": "reportOptionalMemberAccess", "severity": "error", "startCharacter": 41, - "startLine": 2984 + "startLine": 2995 }, { "endCharacter": 37, - "endLine": 2994, + "endLine": 3005, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Cannot assign to attribute \"train_env\" for class \"ReforceXY*\"\n  Type \"None\" is not assignable to type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\"\n    \"None\" is not assignable to \"VecMonitor\"\n    \"None\" is not assignable to \"SubprocVecEnv\"\n    \"None\" is not assignable to \"Env[Unknown, Unknown]\"", "rule": "reportAttributeAccessIssue", "severity": "error", "startCharacter": 33, - "startLine": 2994 + "startLine": 3005 }, { "endCharacter": 36, - "endLine": 2999, + "endLine": 3010, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Cannot assign to attribute \"eval_env\" for class \"ReforceXY*\"\n  Type \"None\" is not assignable to type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\"\n    \"None\" is not assignable to \"VecMonitor\"\n    \"None\" is not assignable to \"SubprocVecEnv\"\n    \"None\" is not assignable to \"Env[Unknown, Unknown]\"", "rule": "reportAttributeAccessIssue", "severity": "error", "startCharacter": 32, - "startLine": 2999 + "startLine": 3010 }, { "endCharacter": 7, - "endLine": 3044, + "endLine": 3055, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Declaration \"MyRLEnv\" is obscured by a declaration of the same name", "rule": "reportRedeclaration", "severity": "error", "startCharacter": 0, - "startLine": 3044 + "startLine": 3055 }, { "endCharacter": 36, - "endLine": 3056, + "endLine": 3067, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Declaration \"_last_closed_trade_tick\" is obscured by a declaration of the same name", "rule": "reportRedeclaration", "severity": "error", "startCharacter": 13, - "startLine": 3056 + "startLine": 3067 }, { "endCharacter": 13, - "endLine": 3644, + "endLine": 3659, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Method \"reset\" overrides class \"BaseEnvironment\" in an incompatible manner\n  Return type mismatch: base method returns type \"tuple[DataFrame, dict[Unknown, Unknown]]\", override returns type \"tuple[NDArray[float32], dict[str, Any]]\"\n    \"tuple[NDArray[float32], dict[str, Any]]\" is not assignable to \"tuple[DataFrame, dict[Unknown, Unknown]]\"\n      Tuple entry 1 is incorrect type\n        \"ndarray[_AnyShape, dtype[float32]]\" is not assignable to \"DataFrame\"", "rule": "reportIncompatibleMethodOverride", "severity": "error", "startCharacter": 8, - "startLine": 3644 + "startLine": 3659 }, { "endCharacter": 26, - "endLine": 3665, + "endLine": 3680, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Type \"tuple[DataFrame, dict[Unknown, Unknown]]\" is not assignable to return type \"tuple[NDArray[float32], dict[str, Any]]\"\n  \"DataFrame\" is not assignable to \"ndarray[_AnyShape, dtype[float32]]\"", "rule": "reportReturnType", "severity": "error", "startCharacter": 15, - "startLine": 3665 + "startLine": 3680 }, { "endCharacter": 55, - "endLine": 3973, + "endLine": 3988, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 44, - "startLine": 3973 + "startLine": 3988 }, { "endCharacter": 55, - "endLine": 3973, + "endLine": 3988, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 44, - "startLine": 3973 + "startLine": 3988 }, { "endCharacter": 59, - "endLine": 3997, + "endLine": 4012, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 48, - "startLine": 3997 + "startLine": 4012 }, { "endCharacter": 59, - "endLine": 3997, + "endLine": 4012, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 48, - "startLine": 3997 + "startLine": 4012 }, { "endCharacter": 24, - "endLine": 4026, + "endLine": 4041, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Method \"_get_observation\" overrides class \"BaseEnvironment\" in an incompatible manner\n  Return type mismatch: base method returns type \"DataFrame\", override returns type \"NDArray[float32]\"\n    \"ndarray[_AnyShape, dtype[float32]]\" is not assignable to \"DataFrame\"", "rule": "reportIncompatibleMethodOverride", "severity": "error", "startCharacter": 8, - "startLine": 4026 + "startLine": 4041 }, { "endCharacter": 12, - "endLine": 4128, + "endLine": 4134, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Method \"step\" overrides class \"Base5ActionRLEnv\" in an incompatible manner\n  Return type mismatch: base method returns type \"tuple[DataFrame, float, bool, Literal[False], dict[str, Unknown]]\", override returns type \"tuple[NDArray[float32], float, bool, bool, dict[str, Any]]\"\n    \"tuple[NDArray[float32], float, bool, bool, dict[str, Any]]\" is not assignable to \"tuple[DataFrame, float, bool, Literal[False], dict[str, Unknown]]\"\n      Tuple entry 1 is incorrect type\n        \"ndarray[_AnyShape, dtype[float32]]\" is not assignable to \"DataFrame\"", "rule": "reportIncompatibleMethodOverride", "severity": "error", "startCharacter": 8, - "startLine": 4128 + "startLine": 4134 }, { "endCharacter": 20, - "endLine": 4318, + "endLine": 4324, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Method \"action_masks\" overrides class \"BaseEnvironment\" in an incompatible manner\n  Return type mismatch: base method returns type \"list[bool]\", override returns type \"NDArray[bool_]\"\n    \"ndarray[_AnyShape, dtype[bool_]]\" is not assignable to \"list[bool]\"", "rule": "reportIncompatibleMethodOverride", "severity": "error", "startCharacter": 8, - "startLine": 4318 + "startLine": 4324 }, { "endCharacter": 40, - "endLine": 4467, + "endLine": 4473, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "\"Figure\" is not exported from module \"matplotlib.pyplot\"", "rule": "reportPrivateImportUsage", "severity": "error", "startCharacter": 34, - "startLine": 4467 + "startLine": 4473 }, { "endCharacter": 54, - "endLine": 4970, + "endLine": 4976, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 45, - "startLine": 4970 + "startLine": 4976 }, { "endCharacter": 54, - "endLine": 4970, + "endLine": 4976, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 45, - "startLine": 4970 + "startLine": 4976 }, { "endCharacter": 50, - "endLine": 4982, + "endLine": 4988, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"object\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"object\" is not assignable to type \"ConvertibleToFloat\"\n    \"object\" is not assignable to \"str\"\n    \"object\" is incompatible with protocol \"Buffer\"\n      \"__buffer__\" is not present\n    \"object\" is incompatible with protocol \"SupportsFloat\"\n      \"__float__\" is not present\n    \"object\" is incompatible with protocol \"SupportsIndex\"\n      \"__index__\" is not present", "rule": "reportArgumentType", "severity": "error", "startCharacter": 37, - "startLine": 4982 + "startLine": 4988 }, { "endCharacter": 72, - "endLine": 4993, + "endLine": 4999, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 70, - "startLine": 4993 + "startLine": 4999 }, { "endCharacter": 72, - "endLine": 4993, + "endLine": 4999, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 70, - "startLine": 4993 + "startLine": 4999 }, { "endCharacter": 73, - "endLine": 5002, + "endLine": 5008, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 71, - "startLine": 5002 + "startLine": 5008 }, { "endCharacter": 73, - "endLine": 5002, + "endLine": 5008, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 71, - "startLine": 5002 + "startLine": 5008 }, { "endCharacter": 58, - "endLine": 5011, + "endLine": 5017, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 56, - "startLine": 5011 + "startLine": 5017 }, { "endCharacter": 58, - "endLine": 5011, + "endLine": 5017, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 56, - "startLine": 5011 + "startLine": 5017 }, { "endCharacter": 50, - "endLine": 5242, + "endLine": 5248, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Mapping[Unknown, Unknown]\" cannot be assigned to parameter \"src\" of type \"dict[str, Any]\" in function \"deepmerge\"\n  \"Mapping[Unknown, Unknown]\" is not assignable to \"dict[str, Any]\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 49, - "startLine": 5242 + "startLine": 5248 }, { "endCharacter": 20, - "endLine": 5419, + "endLine": 5425, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 18, - "startLine": 5419 + "startLine": 5425 }, { "endCharacter": 20, - "endLine": 5419, + "endLine": 5425, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 18, - "startLine": 5419 + "startLine": 5425 }, { "endCharacter": 59, - "endLine": 5424, + "endLine": 5430, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 31, - "startLine": 5424 + "startLine": 5430 }, { "endCharacter": 59, - "endLine": 5424, + "endLine": 5430, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 31, - "startLine": 5424 + "startLine": 5430 }, { "endCharacter": 65, - "endLine": 5425, + "endLine": 5431, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 34, - "startLine": 5425 + "startLine": 5431 }, { "endCharacter": 65, - "endLine": 5425, + "endLine": 5431, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 34, - "startLine": 5425 - }, - { - "endCharacter": 57, - "endLine": 5426, - "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", - "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", - "rule": "reportArgumentType", - "severity": "error", - "startCharacter": 31, - "startLine": 5426 - }, - { - "endCharacter": 57, - "endLine": 5426, - "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", - "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", - "rule": "reportArgumentType", - "severity": "error", - "startCharacter": 31, - "startLine": 5426 + "startLine": 5431 }, { "endCharacter": 63, - "endLine": 5428, + "endLine": 5434, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 34, - "startLine": 5428 + "startLine": 5434 }, { "endCharacter": 63, - "endLine": 5428, + "endLine": 5434, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 34, - "startLine": 5428 + "startLine": 5434 }, { "endCharacter": 61, - "endLine": 5430, + "endLine": 5436, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 32, - "startLine": 5430 + "startLine": 5436 }, { "endCharacter": 61, - "endLine": 5430, + "endLine": 5436, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 32, - "startLine": 5430 + "startLine": 5436 }, { "endCharacter": 67, - "endLine": 5431, + "endLine": 5437, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 36, - "startLine": 5431 + "startLine": 5437 }, { "endCharacter": 67, - "endLine": 5431, + "endLine": 5437, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 36, - "startLine": 5431 + "startLine": 5437 }, { "endCharacter": 73, - "endLine": 5432, + "endLine": 5438, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 39, - "startLine": 5432 + "startLine": 5438 }, { "endCharacter": 73, - "endLine": 5432, + "endLine": 5438, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 39, - "startLine": 5432 + "startLine": 5438 }, { "endCharacter": 61, - "endLine": 5433, + "endLine": 5439, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 33, - "startLine": 5433 + "startLine": 5439 }, { "endCharacter": 61, - "endLine": 5433, + "endLine": 5439, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 33, - "startLine": 5433 + "startLine": 5439 }, { "endCharacter": 89, - "endLine": 5440, + "endLine": 5446, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 52, - "startLine": 5440 + "startLine": 5446 }, { "endCharacter": 89, - "endLine": 5440, + "endLine": 5446, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 52, - "startLine": 5440 + "startLine": 5446 }, { "endCharacter": 83, - "endLine": 5441, + "endLine": 5447, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 49, - "startLine": 5441 + "startLine": 5447 }, { "endCharacter": 83, - "endLine": 5441, + "endLine": 5447, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 49, - "startLine": 5441 - }, - { - "endCharacter": 57, - "endLine": 5466, - "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", - "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", - "rule": "reportArgumentType", - "severity": "error", - "startCharacter": 31, - "startLine": 5466 - }, - { - "endCharacter": 57, - "endLine": 5466, - "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", - "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", - "rule": "reportArgumentType", - "severity": "error", - "startCharacter": 31, - "startLine": 5466 + "startLine": 5447 }, { "endCharacter": 65, - "endLine": 5467, + "endLine": 5473, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 34, - "startLine": 5467 + "startLine": 5473 }, { "endCharacter": 65, - "endLine": 5467, + "endLine": 5473, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 34, - "startLine": 5467 + "startLine": 5473 }, { "endCharacter": 67, - "endLine": 5469, + "endLine": 5475, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 35, - "startLine": 5469 + "startLine": 5475 }, { "endCharacter": 67, - "endLine": 5469, + "endLine": 5475, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 35, - "startLine": 5469 + "startLine": 5475 }, { "endCharacter": 87, - "endLine": 5472, + "endLine": 5478, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 46, - "startLine": 5472 + "startLine": 5478 }, { "endCharacter": 87, - "endLine": 5472, + "endLine": 5478, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 46, - "startLine": 5472 + "startLine": 5478 }, { "endCharacter": 93, - "endLine": 5473, + "endLine": 5479, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 49, - "startLine": 5473 + "startLine": 5479 }, { "endCharacter": 93, - "endLine": 5473, + "endLine": 5479, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 49, - "startLine": 5473 + "startLine": 5479 }, { "endCharacter": 89, - "endLine": 5474, + "endLine": 5480, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 47, - "startLine": 5474 + "startLine": 5480 }, { "endCharacter": 89, - "endLine": 5474, + "endLine": 5480, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n    Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsFloat\"\n        \"__float__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 47, - "startLine": 5474 + "startLine": 5480 }, { "endCharacter": 89, - "endLine": 5475, + "endLine": 5481, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 46, - "startLine": 5475 + "startLine": 5481 }, { "endCharacter": 89, - "endLine": 5475, + "endLine": 5481, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 46, - "startLine": 5475 + "startLine": 5481 }, { "endCharacter": 75, - "endLine": 5476, + "endLine": 5482, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"", "rule": "reportArgumentType", "severity": "error", "startCharacter": 39, - "startLine": 5476 + "startLine": 5482 }, { "endCharacter": 75, - "endLine": 5476, + "endLine": 5482, "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py", "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n    Type \"None\" is not assignable to type \"ConvertibleToInt\"\n      \"None\" is not assignable to \"str\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"None\" is incompatible with protocol \"SupportsIndex\"\n ...", "rule": "reportArgumentType", "severity": "error", "startCharacter": 39, - "startLine": 5476 + "startLine": 5482 }, { "endCharacter": 33, diff --git a/ReforceXY/.coveragerc b/ReforceXY/.coveragerc index a922b88..4aa29b0 100644 --- a/ReforceXY/.coveragerc +++ b/ReforceXY/.coveragerc @@ -8,5 +8,5 @@ relative_files = True show_missing = True precision = 1 include_namespace_packages = True -# measured 2026-10-02 at 75.3% — raise only, never lower +# measured 2026-10-02 at 75.6% — raise only, never lower fail_under = 70 \ No newline at end of file diff --git a/ReforceXY/tests/qa_support.py b/ReforceXY/tests/qa_support.py index 91c9425..4ebedf3 100644 --- a/ReforceXY/tests/qa_support.py +++ b/ReforceXY/tests/qa_support.py @@ -68,13 +68,8 @@ _BASE_CONFIG: dict[str, Any] = { "check_envs": False, "add_state_info": False, }, - # `create_sampler` resolves `auto` through optunahub.load_module, which is an - # outbound fetch to hub.optuna.org, so the sampler is pinned here. The pin holds - # only while callers go through `**overrides`: two tests assign `rl_config_optuna` - # wholesale and would discard it. The guarantee that survives that is in the - # production default — `create_sampler` falls back to "tpe" and raises for anything - # outside `_Samplers`, so no config value reaches the network either way. There is - # no `pruner` key: `create_pruner` is a staticmethod taking three ints. + # Use local TPE by default in QA. Explicit overrides are preserved; `auto` + # loads an OptunaHub sampler and may require network access. "rl_config_optuna": {"enabled": False, "sampler": "tpe"}, }, } diff --git a/ReforceXY/tests/test_model_pbrs_transitions.py b/ReforceXY/tests/test_model_pbrs_transitions.py index db4265d..d49877b 100644 --- a/ReforceXY/tests/test_model_pbrs_transitions.py +++ b/ReforceXY/tests/test_model_pbrs_transitions.py @@ -3,12 +3,15 @@ import math import tempfile import unittest +from pathlib import Path from types import SimpleNamespace +from unittest import mock import numpy as np import pandas as pd from qa_support import QaTestCase, model_config from sb3_contrib import MaskablePPO +from sb3_contrib.common.maskable.evaluation import evaluate_policy from ReforceXY.user_data.freqaimodels.ReforceXY import Actions, MyRLEnv, Positions, ReforceXY @@ -143,6 +146,48 @@ class PbrsTransitionsTest(QaTestCase): self.assertNotEqual(additive, 0.0) self.assertEqual(info["pbrs_invariant"], mode == "canonical") + def test_tiny_terminal_potentials_reconcile_reward_history_and_discounted_sum(self): + for mode, explicit_exit in ( + ("canonical", False), + ("retain_previous", False), + ("retain_previous", True), + ): + with self.subTest(mode=mode, explicit_exit=explicit_exit): + shaped = self.env(fee=0.0015, hold_potential_ratio=1e-10, exit_potential_mode=mode) + base = self.env(fee=0.0015, hold_potential_enabled=False, exit_potential_mode=mode) + shaping = [] + for tick in range(20): + action = Actions.Long_enter if tick == 0 else Actions.Neutral + if explicit_exit and tick == 2: + action = Actions.Long_exit + _, reward, done, truncated, _ = shaped.step(action.value) + _, base_reward, base_done, base_truncated, _ = base.step(action.value) + self.assertEqual((done, truncated), (base_done, base_truncated)) + expected = 0.8 * shaped._last_next_potential - shaped._last_prev_potential + self.assertEqual(shaped._last_reward_shaping, expected) + self.assertAlmostEqual(reward - base_reward, expected, places=14) + shaping.append(expected) + if done or truncated: + break + self.assertTrue(done or truncated) + self.assertGreater(abs(shaped._last_prev_potential), 0.0) + self.assertLess(abs(shaped._last_prev_potential), 1e-8) + self.assertEqual(shaped._last_next_potential, 0.0) + self.assertEqual(shaped._last_reward_shaping, -shaped._last_prev_potential) + self.assertAlmostEqual( + math.fsum(0.8**t * f for t, f in enumerate(shaping)), 0.0, places=20 + ) + self.assertAlmostEqual(shaped._total_reward_shaping, math.fsum(shaping), places=20) + self.assertEqual(len(shaped.trade_history), 2) + history = shaped.get_env_history() + self.assertEqual(history.iloc[-1]["reward_shaping"], -shaped._last_prev_potential) + self.assertEqual(history.iloc[-1]["next_potential"], 0.0) + + def test_standalone_environment_rejects_invalid_potential_discounts(self): + for gamma in (None, math.nan, math.inf, -math.inf, -0.1, 1.1, True, "0.8"): + with self.subTest(gamma=gamma), self.assertRaises(ValueError): + self.env(potential_gamma=gamma) + def test_reset_discards_the_previous_episode_potential_and_additive_totals(self): env = self.env( exit_potential_mode="retain_previous", entry_additive_enabled=True, fee=0.0015 @@ -241,6 +286,48 @@ class DiscountResolutionTest(QaTestCase): with self.assertRaises(ValueError): model.pack_env_dict("BTC/USDT", {"gamma": None}) + def test_effective_discount_requires_a_finite_real_scalar_in_unit_interval(self): + model = self.model(gamma=0.83) + for gamma in ( + math.nan, + math.inf, + -math.inf, + -0.1, + 1.1, + True, + np.bool_(False), + "0.8", + 0.8 + 0j, + [0.8], + np.array(0.8), + np.nextafter(np.longdouble(1), np.longdouble(math.inf)), + ): + with self.subTest(gamma=gamma), self.assertRaises(ValueError): + model.pack_env_dict("BTC/USDT", {"gamma": gamma}) + for gamma in (0, 1, np.int64(1), np.float32(0.79), np.float64(0.83)): + with self.subTest(gamma=gamma): + kwargs = model.pack_env_dict("BTC/USDT", {"gamma": gamma}) + resolved = kwargs["config"]["freqai"]["rl_config"]["model_reward_parameters"][ + "potential_gamma" + ] + self.assertIs(type(resolved), float) + self.assertEqual(resolved, float(gamma)) + prices = pd.DataFrame({"open": [100.0] * 16}) + env = MyRLEnv(df=prices.copy(), prices=prices, **kwargs) + self.addCleanup(env.close) + learner = MaskablePPO( + "MlpPolicy", + env, + gamma=resolved, + n_steps=8, + batch_size=8, + n_epochs=1, + device="cpu", + ) + learner.learn(8) + self.assertEqual(learner.gamma, env._potential_gamma) + self.assertGreater(learner._n_updates, 0) + def test_invalid_replacement_discount_does_not_close_running_environments(self): model = self.model(gamma=0.83) features = pd.DataFrame({"f": np.arange(16, dtype=float)}) @@ -250,8 +337,13 @@ class DiscountResolutionTest(QaTestCase): model.set_train_and_eval_environments(data, prices, prices, kitchen) running_train, running_eval = model.train_env, model.eval_env first = running_train.reset() - with self.assertRaises(ValueError): - model.set_train_and_eval_environments(data, prices, prices, kitchen, {"gamma": None}) + for gamma in (None, math.nan, math.inf, -math.inf, -0.1, 1.1, True, "0.8"): + with self.subTest(gamma=gamma), self.assertRaises(ValueError): + model.set_train_and_eval_environments( + data, prices, prices, kitchen, {"gamma": gamma} + ) + self.assertIs(model.train_env, running_train) + self.assertIs(model.eval_env, running_eval) self.assertIs(model.train_env, running_train) self.assertIs(model.eval_env, running_eval) second, _, done, _ = running_train.step([Actions.Neutral.value]) @@ -272,6 +364,61 @@ class DiscountResolutionTest(QaTestCase): self.assertEqual(learner.gamma, env._potential_gamma) self.assertGreater(learner._n_updates, 0) + def test_persisted_numpy_learner_discount_overrides_finite_and_null_base(self): + with tempfile.TemporaryDirectory() as temp: + gamma = np.float32(0.79) + prices = pd.DataFrame({"open": [100.0] * 16}) + for base in (0.95, None): + with self.subTest(base=base): + owner = self.model(gamma=base) + kwargs = owner.pack_env_dict("BTC/USDT", {"gamma": gamma}) + env = MyRLEnv(df=prices.copy(), prices=prices, **kwargs) + self.addCleanup(env.close) + learner = MaskablePPO( + "MlpPolicy", + env, + gamma=gamma, + n_steps=8, + batch_size=8, + n_epochs=1, + device="cpu", + ) + learner.learn(8) + archive = Path(temp) / f"learner-{base}" + learner.save(archive) + loaded = MaskablePPO.load(archive) + self.assertIsInstance(loaded.gamma, np.floating) + previous_updates = loaded._n_updates + observed = [] + + def evaluate(policy, environment, observed=observed, **parameters): + observed.append( + ( + policy.gamma, + policy.get_env().get_attr("_potential_gamma"), + environment.get_attr("_potential_gamma"), + ) + ) + return evaluate_policy(policy, environment, **parameters) + + data = {"train_features": prices.copy(), "test_features": prices.copy()} + kitchen = SimpleNamespace(pair="BTC/USDT", data_path=Path(temp) / f"fit-{base}") + kitchen.data_path.mkdir() + with mock.patch( + "ReforceXY.user_data.freqaimodels.ReforceXY.evaluate_policy", + side_effect=evaluate, + ): + continued = owner.fit( + data, + kitchen, + prices_train=prices, + prices_test=prices, + deployment_state=(loaded, None), + ) + self.assertEqual(observed, [(gamma, [float(gamma)], [float(gamma)])]) + self.assertEqual(float(continued.gamma), float(gamma)) + self.assertGreater(loaded._n_updates, previous_updates) + if __name__ == "__main__": unittest.main() diff --git a/ReforceXY/tests/test_model_training_observations.py b/ReforceXY/tests/test_model_training_observations.py index 4748f68..c57fee9 100644 --- a/ReforceXY/tests/test_model_training_observations.py +++ b/ReforceXY/tests/test_model_training_observations.py @@ -1,5 +1,6 @@ """Regression contracts for learning eligibility, replay and temporal observations.""" +import json import tempfile from pathlib import Path from types import SimpleNamespace @@ -10,7 +11,7 @@ import pandas as pd from freqtrade.enums import RunMode from freqtrade.exceptions import DependencyException from freqtrade.exchange import timeframe_to_seconds -from freqtrade.freqai.data_drawer import FreqaiDataDrawer +from freqtrade.freqai.data_drawer import METADATA, FreqaiDataDrawer from freqtrade.freqai.data_kitchen import FreqaiDataKitchen from optuna import TrialPruned, create_study from qa_support import QaTestCase, RecordingPolicy, model_config @@ -80,6 +81,42 @@ class TrainingObservationsTest(QaTestCase): np.testing.assert_array_equal(trained.replay_buffer.observations, replay) self.assertEqual(restored.replay_buffer.size(), 0) self.assertIs(model.dd.load_data(dk.pair, dk), restored) + compatible, pipeline = model._resolve_deployment_state(dk, dk.pair) + previous_updates = compatible._n_updates + continued_dk = FreqaiDataKitchen(config, live=True, pair=dk.pair) + continued_dk.data_path = Path(temp) / "continued" + continued_dk.data_path.mkdir() + model.fit( + dk.data_dictionary, + continued_dk, + prices_train=dk.data_dictionary["train_prices"], + prices_test=dk.data_dictionary["test_prices"], + deployment_state=(compatible, pipeline), + ) + self.assertGreater(compatible._n_updates, previous_updates) + metadata_path = dk.data_path / f"{dk.model_filename}_{METADATA}.json" + metadata = json.loads(metadata_path.read_text()) + current_generation = metadata[model._DEPLOYMENT_COORDINATE_MARKER_KEY] + metadata[model._DEPLOYMENT_COORDINATE_MARKER_KEY] = ( + "chronological-frozen-pipelines-v2" + ) + metadata_path.write_text(json.dumps(metadata)) + for cached in (False, True): + with self.subTest(legacy_cached=cached): + model.dd.model_dictionary.clear() + model.dd.meta_data_dictionary.clear() + if cached: + inference = model.dd.load_data(dk.pair, dk) + action, _ = inference.predict( + np.zeros(inference.observation_space.shape, dtype=np.float32), + deterministic=True, + ) + self.assertTrue(inference.action_space.contains(action)) + with self.assertRaisesRegex(DependencyException, "Reset trained models"): + model._resolve_deployment_state(dk, dk.pair) + metadata[model._DEPLOYMENT_COORDINATE_MARKER_KEY] = current_generation + metadata_path.write_text(json.dumps(metadata)) + model.dd.meta_data_dictionary.clear() model.dd.model_dictionary.clear() (dk.data_path / dk.data["reforcexy_replay"]).unlink() inference_model = model.dd.load_data(dk.pair, dk) diff --git a/ReforceXY/tests/test_strategy_semantics.py b/ReforceXY/tests/test_strategy_semantics.py index 292623c..23ba4e6 100644 --- a/ReforceXY/tests/test_strategy_semantics.py +++ b/ReforceXY/tests/test_strategy_semantics.py @@ -2,7 +2,6 @@ import unittest from datetime import datetime, timezone -from types import SimpleNamespace from unittest import mock import numpy as np @@ -270,43 +269,31 @@ class ExitSignalTest(QaTestCase): self.assertFalse(_raised(result["exit_long"])[0]) self.assertFalse(_raised(result["exit_short"])[0]) - def test_a_rejected_prediction_closes_the_open_position_of_its_own_side(self): - # do_predict == 2 is a rejected prediction: the open trade must be closed, and - # its side decides which flag is set, not the recorded action. - frame = _frame([1], do_predict=2) - for is_short, expected in ((False, "exit_long"), (True, "exit_short")): - with self.subTest(is_short=is_short): - trade = SimpleNamespace(is_short=is_short) - with mock.patch( - "ReforceXY.user_data.strategies.RLAgentStrategy.Trade.get_trades_proxy", - return_value=[trade], - ): - result = self._strategy().populate_exit_trend( - frame.copy(), {"pair": "BTC/USDT"} - ) - self.assertTrue(_raised(result[expected])[0]) - other = "exit_short" if expected == "exit_long" else "exit_long" - self.assertFalse(_raised(result[other])[0]) - - def test_a_rejected_prediction_ignores_closed_positions(self): - # Reached through freqtrade's own backtest collections rather than by asserting - # the call arguments, so a strategy that filtered differently would still pass. - # With `is_open` dropped the proxy returns closed trades too, and this goes red. - closed = SimpleNamespace(pair="BTC/USDT", is_open=False, is_short=False) - opened = SimpleNamespace(pair="BTC/USDT", is_open=True, is_short=True) - for open_trades, expected_short in (([], False), ([opened], True)): - with self.subTest(open_short=expected_short): + def test_an_expired_model_closes_only_open_positions_for_the_current_pair(self): + closed = LocalTrade(pair="BTC/USDT", is_open=False, is_short=False) + long = LocalTrade(pair="BTC/USDT", is_open=True, is_short=False) + short = LocalTrade(pair="BTC/USDT", is_open=True, is_short=True) + unrelated_long = LocalTrade(pair="ETH/USDT", is_open=True, is_short=False) + unrelated_short = LocalTrade(pair="ETH/USDT", is_open=True, is_short=True) + for open_trades, expected in ( + ([], (False, False)), + ([short], (False, True)), + ([long, unrelated_short], (True, False)), + ([short, unrelated_long], (False, True)), + ([unrelated_long], (False, False)), + ([unrelated_short], (False, False)), + ): + with self.subTest(expected=expected, trades=open_trades): with ( mock.patch.object(Trade, "use_db", False), mock.patch.object(LocalTrade, "bt_trades", [closed]), mock.patch.object(LocalTrade, "bt_trades_open", open_trades), ): result = self._strategy().populate_exit_trend( - _frame([Actions.Neutral.value], do_predict=2), - {"pair": "BTC/USDT"}, + _frame([Actions.Neutral.value], do_predict=2), {"pair": "BTC/USDT"} ) - self.assertEqual([False], _raised(result["exit_long"])) - self.assertEqual([expected_short], _raised(result["exit_short"])) + self.assertEqual([expected[0]], _raised(result["exit_long"])) + self.assertEqual([expected[1]], _raised(result["exit_short"])) def test_a_row_without_a_prediction_raises_no_exit(self): result = self._strategy().populate_exit_trend( @@ -319,16 +306,6 @@ class ExitSignalTest(QaTestCase): self.assertEqual([False, False], _raised(result["exit_long"])) self.assertEqual([False, False], _raised(result["exit_short"])) - def test_a_rejected_prediction_with_no_open_trade_raises_no_exit(self): - frame = _frame([1], do_predict=2) - with mock.patch( - "ReforceXY.user_data.strategies.RLAgentStrategy.Trade.get_trades_proxy", - return_value=[], - ): - result = self._strategy().populate_exit_trend(frame, {"pair": "BTC/USDT"}) - self.assertFalse(_raised(result["exit_long"])[0]) - self.assertFalse(_raised(result["exit_short"])[0]) - class FeatureEngineeringTest(QaTestCase): def _strategy(self): diff --git a/ReforceXY/tests/test_suite_contract.py b/ReforceXY/tests/test_suite_contract.py index 146bbb5..e9b039f 100644 --- a/ReforceXY/tests/test_suite_contract.py +++ b/ReforceXY/tests/test_suite_contract.py @@ -159,35 +159,82 @@ class SuiteContractTest(unittest.TestCase): finally: reseed(previous) - def test_the_restore_puts_the_process_globals_back(self): + def test_the_lifecycle_restores_globals_before_body_and_after_all_outcomes(self): cache = _PRODUCTION.ReforceXY._action_masks_cache - # Dirty every global the way a test that trains a model would. - cache[("dirty", 0.5)] = None - random.seed(1234) - np.random.seed(1234) - torch.manual_seed(1234) - self.addCleanup(QaTestCase._restore_process_globals) - QaTestCase._restore_process_globals() + def snapshot(): + return ( + dict(cache), + random.getstate(), + np.random.get_state(), + torch.random.get_rng_state().clone(), + ) - self.assertEqual( - dict(_ACTION_MASKS_CACHE_AT_IMPORT), - dict(cache), - "_action_masks_cache was not restored", - ) - self.assertEqual(_RANDOM_STATE_AT_IMPORT, random.getstate()) - self.assertEqual( - _NUMPY_STATE_AT_IMPORT[1].tolist(), - np.random.get_state()[1].tolist(), - "the numpy bit generator was not rewound", - ) - self.assertEqual( - int(_NUMPY_STATE_AT_IMPORT[2]), - int(np.random.get_state()[2]), - "the numpy stream position advanced and was not restored", - ) - if _TORCH_STATE_AT_IMPORT is not None: - self.assertTrue(torch.equal(torch.random.get_rng_state(), _TORCH_STATE_AT_IMPORT)) + entry = snapshot() + + def restore_entry(): + cache.clear() + cache.update(entry[0]) + random.setstate(entry[1]) + np.random.set_state(entry[2]) + torch.random.set_rng_state(entry[3]) + + self.addCleanup(restore_entry) + + def dirty(): + cache[("lifecycle-probe", 0.5)] = None + random.seed(1234) + np.random.seed(1234) + torch.manual_seed(1234) + + def assert_baseline(state): + self.assertEqual(state[0], dict(_ACTION_MASKS_CACHE_AT_IMPORT)) + self.assertEqual(state[1], _RANDOM_STATE_AT_IMPORT) + self.assertEqual(state[2][0], _NUMPY_STATE_AT_IMPORT[0]) + np.testing.assert_array_equal(state[2][1], _NUMPY_STATE_AT_IMPORT[1]) + self.assertEqual(state[2][2:], _NUMPY_STATE_AT_IMPORT[2:]) + if _TORCH_STATE_AT_IMPORT is not None: + self.assertTrue(torch.equal(state[3], _TORCH_STATE_AT_IMPORT)) + + class Probe(QaTestCase): + def __init__(self, outcome): + super().__init__() + self.outcome = outcome + self.observed = [] + + def setUp(self): + super().setUp() + self.observed.append(snapshot()) + if self.outcome == "setup-error": + dirty() + raise RuntimeError("intentional setup-error") + + def runTest(self): + self.observed.append(snapshot()) + dirty() + if self.outcome == "body-failure": + self.fail("intentional body-failure") + + def tearDown(self): + if self.outcome == "teardown-error": + dirty() + raise RuntimeError("intentional teardown-error") + + for outcome in ("success", "body-failure", "setup-error", "teardown-error"): + with self.subTest(outcome=outcome): + dirty() + result = unittest.TestResult() + probe = Probe(outcome) + probe.run(result) + self.assertEqual(result.testsRun, 1) + self.assertEqual(len(probe.observed), 1 if outcome == "setup-error" else 2) + for state in probe.observed: + assert_baseline(state) + assert_baseline(snapshot()) + self.assertEqual(len(result.failures), int(outcome == "body-failure")) + self.assertEqual(len(result.errors), int(outcome.endswith("error"))) + for _, traceback in result.failures + result.errors: + self.assertIn(f"intentional {outcome}", traceback) if __name__ == "__main__": diff --git a/ReforceXY/user_data/freqaimodels/ReforceXY.py b/ReforceXY/user_data/freqaimodels/ReforceXY.py index ffdcfcb..b6d1ab2 100644 --- a/ReforceXY/user_data/freqaimodels/ReforceXY.py +++ b/ReforceXY/user_data/freqaimodels/ReforceXY.py @@ -433,7 +433,7 @@ class ReforceXY(BaseReinforcementLearningModel): _LOG_2: Final[float] = math.log(2.0) _DEPLOYMENT_COORDINATE_MARKER_KEY: Final[str] = "reforcexy_deployment_coordinates" - _DEPLOYMENT_COORDINATE_GENERATION: Final[str] = "chronological-frozen-pipelines-v2" + _DEPLOYMENT_COORDINATE_GENERATION: Final[str] = "chronological-frozen-pipelines-pbrs-v3" DEFAULT_BASE_FACTOR: Final[float] = 100.0 DEFAULT_DISCOUNT_GAMMA: Final[float] = 0.95 @@ -549,7 +549,7 @@ class ReforceXY(BaseReinforcementLearningModel): _BEST_PARAMS_LOCK_FILENAME: Final[str] = ".hyperopt-best-params.lock" # Bump on objective changes that make persisted trials or best params incompatible. _OPTUNA_OBJECTIVE_IDENTITY: Final[str] = ( - "terminal-liquidation-risk-normalized-trained-policy-v4" + "terminal-liquidation-risk-normalized-trained-policy-v5" ) _PPO_N_STEPS: Final[tuple[int, ...]] = (512, 1024, 2048, 4096) _PPO_N_STEPS_MIN: Final[int] = min(_PPO_N_STEPS) @@ -952,13 +952,21 @@ class ReforceXY(BaseReinforcementLearningModel): @staticmethod def _resolve_discount_gamma(model_params: Mapping[str, Any]) -> float: - """Resolve discount after precedence, rejecting explicit null instead of defaulting.""" + """Validate the winning Python/NumPy real scalar discount and normalize to float.""" gamma = model_params.get("gamma", ReforceXY.DEFAULT_DISCOUNT_GAMMA) if gamma is None: raise ValueError( "Config [global]: effective model_training_parameters.gamma must not be null" ) - return cast("float", gamma) + if ( + isinstance(gamma, (bool, np.bool_)) + or not isinstance(gamma, (int, float, np.integer, np.floating)) + or not 0 <= gamma <= 1 + ): + raise ValueError( + "Config [global]: effective discount gamma must be a finite real scalar in [0, 1]" + ) + return float(gamma) def set_train_and_eval_environments( self, @@ -1315,6 +1323,7 @@ class ReforceXY(BaseReinforcementLearningModel): cached = self.dd.meta_data_dictionary.get(pair, {}) metadata = cached.get(METADATA) feature_pipeline = cached.get(FEATURE_PIPELINE) + prefix: Path | None = None if model is None or metadata is None or feature_pipeline is None: # The current kitchen points to the new window, not deployed files. previous_dk = copy.copy(dk) @@ -1324,21 +1333,23 @@ class ReforceXY(BaseReinforcementLearningModel): if metadata is None: with Path(f"{prefix}_{METADATA}.json").open("r") as fp: metadata = rapidjson.load(fp, number_mode=METADATA_NUMBER_MODE) - if feature_pipeline is None: - with Path(f"{prefix}_{FEATURE_PIPELINE}.pkl").open("rb") as fp: - feature_pipeline = cloudpickle.load(fp) - if model is None: - model = self.MODELCLASS.load(Path(f"{prefix}_model")) - self._restore_replay(model, metadata, previous_dk.data_path, pair) if ( metadata.get(self._DEPLOYMENT_COORDINATE_MARKER_KEY) != self._DEPLOYMENT_COORDINATE_GENERATION ): raise ValueError( - "persisted deployment coordinate generation is missing or incompatible" + "persisted deployment coordinate/reward generation is missing or incompatible" ) + if feature_pipeline is None: + assert prefix is not None + with Path(f"{prefix}_{FEATURE_PIPELINE}.pkl").open("rb") as fp: + feature_pipeline = cloudpickle.load(fp) + if model is None: + assert prefix is not None + model = self.MODELCLASS.load(Path(f"{prefix}_model")) if not isinstance(model, self.MODELCLASS): raise ValueError("persisted policy type differs from the configured model") + ReforceXY._resolve_discount_gamma({"gamma": getattr(model, "gamma", None)}) for name, expected, actual in ( ("features", dk.training_features_list, metadata["training_features_list"]), ("labels", dk.label_list, metadata["label_list"]), @@ -1350,6 +1361,8 @@ class ReforceXY(BaseReinforcementLearningModel): ): if list(expected) != list(actual): raise ValueError(f"persisted {name} differ in names or order") + if cached_model is None: + self._restore_replay(model, metadata, Path(previous["data_path"]), pair) if cached_model is not None: # SB3 archives preserve policy/optimizer state but exclude envs and loggers. with BytesIO() as archive: @@ -1570,9 +1583,7 @@ class ReforceXY(BaseReinforcementLearningModel): model = deployment_state[0] if deployment_state is not None else None effective_params = dict(model_params) if model is not None: - learner_gamma = getattr(model, "gamma", None) - if isinstance(learner_gamma, (int, float)) and np.isfinite(learner_gamma): - effective_params["gamma"] = float(learner_gamma) + effective_params["gamma"] = getattr(model, "gamma", None) effective_params["gamma"] = ReforceXY._resolve_discount_gamma(effective_params) # Preserve raw prices and the resumed learner's discount in its environments. try: @@ -3087,8 +3098,12 @@ class MyRLEnv(Base5ActionRLEnv): ) ) # === PBRS COMMON PARAMETERS === - self._potential_gamma = float( - model_reward_parameters.get("potential_gamma", ReforceXY.DEFAULT_DISCOUNT_GAMMA) + self._potential_gamma = ReforceXY._resolve_discount_gamma( + { + "gamma": model_reward_parameters.get( + "potential_gamma", ReforceXY.DEFAULT_DISCOUNT_GAMMA + ) + } ) if np.isclose(self._potential_gamma, 0.0): logger.warning( @@ -4111,15 +4126,6 @@ class MyRLEnv(Base5ActionRLEnv): computed_reward_shaping = self._last_reward_shaping terminal_reward_shaping = -prev_potential reward_shaping_delta = terminal_reward_shaping - computed_reward_shaping - last_next_potential = self._last_next_potential - - if np.isclose(computed_reward_shaping, terminal_reward_shaping) and np.isclose( - last_next_potential, 0.0 - ): - self._last_potential = 0.0 - self._last_next_potential = 0.0 - return reward - self._last_potential = 0.0 self._last_next_potential = 0.0 self._last_reward_shaping = terminal_reward_shaping @@ -5424,7 +5430,7 @@ def convert_optuna_params_to_model_params( { "n_steps": int(optuna_params.get("n_steps")), "batch_size": int(optuna_params.get("batch_size")), - "gamma": float(optuna_params.get("gamma")), + "gamma": ReforceXY._resolve_discount_gamma(optuna_params), "learning_rate": lr, "ent_coef": float(optuna_params.get("ent_coef")), "clip_range": cr, @@ -5464,7 +5470,7 @@ def convert_optuna_params_to_model_params( model_params.update( { - "gamma": float(optuna_params.get("gamma")), + "gamma": ReforceXY._resolve_discount_gamma(optuna_params), "batch_size": int(optuna_params.get("batch_size")), "learning_rate": lr, "buffer_size": int(optuna_params.get("buffer_size")),