From 1dbeb212be645e48bf17b96b9744d7b3fd97d524 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Sun, 23 Aug 2026 21:22:19 +0800 Subject: [PATCH] fix: align legacy plugin policies with no-order contract Co-Authored-By: Codex --- docs/market-regime-control-plan.md | 20 ++++------ docs/market-regime-control-plan.zh-CN.md | 14 +++---- docs/plugin_lifecycle_policy.md | 33 +++++++---------- docs/plugin_lifecycle_policy.zh-CN.md | 26 +++++-------- src/quant_strategy_plugins/plugin_catalog.py | 6 ++- src/quant_strategy_plugins/plugin_policies.py | 20 ++++++---- .../strategy_plugin_runner.py | 9 ++++- tests/test_plugin_catalog.py | 8 ++-- tests/test_plugin_policies.py | 8 ++-- tests/test_strategy_plugin_runner.py | 37 +++++++------------ 10 files changed, 84 insertions(+), 97 deletions(-) diff --git a/docs/market-regime-control-plan.md b/docs/market-regime-control-plan.md index 73ea1be..2f44dce 100644 --- a/docs/market-regime-control-plan.md +++ b/docs/market-regime-control-plan.md @@ -144,13 +144,12 @@ allowlist: - `notification_allowed`: the runner may generate and distribute notification artifacts. -- `position_control_allowed`: a strategy runtime may automatically consume - position-control fields. +- `position_control_allowed`: legacy compatibility field; V2 outputs keep it + false and expose any old position-control-shaped data as shadow metadata. - `evidence_status`: records whether the strategy/plugin pair is `automation_approved`, `notification_only`, or `deprecated_compatibility`. -- When `position_control_allowed = true`, the runner output should also expose - a machine-readable `auditable_position_control` block with - `evidence_package_id`, `evidence_valid_until`, and `bounded_budget`. +- Historical `auditable_position_control` evidence remains readable for replay, + but does not grant allocation authority. - `since_version`: records the runner schema version where the permission became effective. @@ -159,18 +158,15 @@ the human notification body: - The plugin repository only writes artifacts and notifications. It does not call broker APIs or directly mutate account allocation. -- Automated position impact happens only when the strategy side explicitly - consumes `position_control`, and only when `position_control_allowed = true` - and `evidence_status = automation_approved`. +- Automated position impact must be generated by an owning strategy candidate + and pass the central Risk Gate; this plugin artifact cannot cause it directly. - New or expanded automated position consumers should clear a 25-30 year long-history validation gate before promotion. For TQQQ/SOXL-style products without enough live ETF history, the long replay must explicitly use a synthetic daily-reset 3x proxy built from the underlying QQQ/SOXX series and archive synthetic and real-ETF evidence separately. -- The current automation-approved strategy consumers are TQQQ growth/income - and SOXL/SOXX trend/income. Global ETF, Russell 1000, and Mega Cap rotation - remain notification/evidence artifacts for this plugin until their own - long-history promotion packages are archived. Their runner artifacts carry +- TQQQ growth/income and SOXL/SOXX trend/income keep their historical evidence, + but all strategy mounts are now notification/evidence artifacts. Their runner artifacts carry `position_control_allowed = false`, `strategy_runtime_metadata_allowed = false`, and `capital_impact = notification_only`. diff --git a/docs/market-regime-control-plan.zh-CN.md b/docs/market-regime-control-plan.zh-CN.md index 515e8ac..e408d27 100644 --- a/docs/market-regime-control-plan.zh-CN.md +++ b/docs/market-regime-control-plan.zh-CN.md @@ -85,21 +85,21 @@ 策略插件 runner 使用显式消费权限 registry,而不是只维护松散 allowlist: - `notification_allowed`:允许生成和分发通知 artifact。 -- `position_control_allowed`:允许策略 runtime 自动消费仓位控制字段。 +- `position_control_allowed`:旧兼容字段;V2 输出固定为 false,旧仓位控制形状的 + 数据只作为 shadow 元数据。 - `evidence_status`:记录该策略/插件组合是 `automation_approved`、`notification_only` 还是 `deprecated_compatibility`。 -- 当 `position_control_allowed = true` 时,runner 输出还应暴露机器可读的 - `auditable_position_control` 块,包含 `evidence_package_id`、 - `evidence_valid_until` 和 `bounded_budget`。 +- 历史 `auditable_position_control` 证据仍可用于回放,但不授予仓位权限。 - `since_version`:记录该消费权限从哪个 runner schema 开始生效。 权限边界写在文档和机器字段里,不重复写进人工通知正文: - 插件仓库只生成 artifact 和通知,不调用券商接口,也不直接改账户配置。 -- 自动仓位影响只发生在策略侧显式消费 `position_control` 时,并且必须同时满足 - `position_control_allowed = true` 和 `evidence_status = automation_approved`。 +- 自动仓位影响必须由归属策略候选生成并通过中央 Risk Gate;插件 artifact + 不能直接造成仓位变化。 - 新增或扩大自动仓位消费范围前,应先通过 25-30 年长周期验证。TQQQ/SOXL 这类实盘产品历史不足的策略,长周期验证必须明确使用 QQQ/SOXX 等底层资产合成的 3x 日重置代理,并把 synthetic 口径和真实 ETF 口径分开归档。 -- 当前已批准自动消费的策略级消费者只有 TQQQ 增长收益和 SOXL/SOXX 趋势收益。Global ETF、Russell 1000 和 Mega Cap 轮动在各自长周期推广包归档前,只保留通知和证据 artifact;runner artifact 会写入 +- TQQQ 增长收益和 SOXL/SOXX 趋势收益保留历史验证证据,但所有策略挂载现在 + 都只保留通知和证据 artifact;runner artifact 会写入 `position_control_allowed = false`、`strategy_runtime_metadata_allowed = false` 和 `capital_impact = notification_only`。 - 同一个自动化证据可以有偏进攻和偏保守两种策略侧消费偏好;插件只输出确定性字段和证据,具体选用哪个偏好由策略配置决定。 diff --git a/docs/plugin_lifecycle_policy.md b/docs/plugin_lifecycle_policy.md index 7c32c67..51cf7f4 100644 --- a/docs/plugin_lifecycle_policy.md +++ b/docs/plugin_lifecycle_policy.md @@ -23,27 +23,19 @@ permission by accident. | `notification_only` | Can notify humans, but cannot control position | none | | `shadow_observer` | Can be attached to runtime metadata and audit trails | none | | `automation_candidate` | Has enough evidence to be considered for automation | gated | -| `automation_approved` | Strategy-side automation is allowed when the platform gate also passes | yes | +| `automation_approved` | Legacy evidence label retained for replay; not direct allocation authority | none | | `deprecated_compatibility` | Kept for replay or staged migration only | none | -## Three-Gate Rule +## V2 Authority Rule -For any plugin-driven capital impact, all three gates must pass: +Plugin artifacts never carry direct capital authority. They may provide a +signal, observation, or bounded risk suggestion to an owning strategy +candidate. That strategy must validate the behavior through its lifecycle and +submit any target through the central Risk Gate. -1. **Plugin schema gate** - - The artifact must match a supported schema version and remain in `shadow` - mode for the shared contract. -2. **Plugin evidence gate** - - The plugin must be marked `automation_approved` and - `position_control_allowed = true`. - - If the platform enables automated position control, the runner should also - carry a machine-readable `auditable_position_control` block with - `evidence_package_id`, `evidence_valid_until`, and `bounded_budget`. -3. **Strategy/platform gate** - - The consuming strategy must explicitly opt in to the plugin and remain - allowed by the platform catalog. - -If any gate fails, the plugin should stay notification-only or compatibility-only. +Legacy v1 `position_control_allowed` and `automation_approved` fields are kept +readable for historical artifacts, but the runner emits them as +notification/shadow-only and cannot use them to mutate allocations. ## Current Policy Shape @@ -59,7 +51,8 @@ If any gate fails, the plugin should stay notification-only or compatibility-onl ## Recommended Operating Rules - Keep `notification_allowed` broad for research visibility. -- Keep `position_control_allowed` narrow and explicit. +- Keep `position_control_allowed = false`; strategy-owned adapters consume + validated signals through the central Risk Gate. - Prefer a single shared policy registry instead of spreading allowlists across runners. - When a strategy consumes a plugin for live capital impact, keep the platform @@ -69,7 +62,7 @@ If any gate fails, the plugin should stay notification-only or compatibility-onl - If the artifact is only for human review, use `notification_only`. - If the artifact is still a sidecar evidence layer, use `shadow_observer`. -- If the plugin is being prepared for automation, keep it in - `automation_candidate` until the strategy gate also passes. +- If plugin behavior is being prepared for automation, promote a new owning + strategy candidate; do not promote the plugin into allocation authority. - If the plugin is no longer the preferred path, mark it `deprecated_compatibility` and keep it out of new runtime defaults. diff --git a/docs/plugin_lifecycle_policy.zh-CN.md b/docs/plugin_lifecycle_policy.zh-CN.md index baee9dd..36250e0 100644 --- a/docs/plugin_lifecycle_policy.zh-CN.md +++ b/docs/plugin_lifecycle_policy.zh-CN.md @@ -21,24 +21,17 @@ | `notification_only` | 可以通知人工,但不能控制仓位 | 无 | | `shadow_observer` | 可以挂到 runtime metadata 和审计轨迹 | 无 | | `automation_candidate` | 证据足够,进入自动化候选 | 受门槛控制 | -| `automation_approved` | 当平台门槛也通过时,策略侧可自动消费 | 有 | +| `automation_approved` | 为历史回放保留的旧证据标签,不代表直接仓位权限 | 无 | | `deprecated_compatibility` | 仅用于回放或迁移兼容 | 无 | -## 三道门槛 +## V2 权限规则 -任何由插件驱动的资金影响,都必须同时通过三道门槛: +插件 artifact 永远不携带直接资金权限。它只能向归属策略候选提供信号、观察或 +受限风险建议;策略必须通过自己的生命周期验证,并把仓位目标提交中央 Risk Gate。 -1. **插件 schema 门槛** - - artifact 必须匹配支持的 schema version,并在共享契约中保持 `shadow` 模式。 -2. **插件证据门槛** - - 插件必须标记为 `automation_approved`,且 `position_control_allowed = true`。 - - 如果平台启用自动仓位控制,runner 还应携带机器可读的 - `auditable_position_control` 块,包含 `evidence_package_id`、 - `evidence_valid_until` 和 `bounded_budget`。 -3. **策略 / 平台门槛** - - 消费策略必须显式 opt-in,并且仍然被平台 catalog 允许。 - -任意一项失败,插件就应该停留在 notification-only 或兼容模式。 +旧 v1 的 `position_control_allowed` 和 `automation_approved` 字段继续可读, +方便历史 artifact 回放;但 runner 统一输出为 notification/shadow-only,不能 +借这些字段修改仓位。 ## 当前策略形态 @@ -53,7 +46,8 @@ ## 推荐运行规则 - `notification_allowed` 可以保持宽松,方便研究可见。 -- `position_control_allowed` 必须保持窄而明确。 +- `position_control_allowed` 固定为 `false`;策略侧适配器只通过中央 Risk Gate + 消费已经验证的信号。 - 尽量使用统一的 policy registry,不要把 allowlist 分散到多个 runner。 - 当策略消费插件并产生 live 资金影响时,平台通知路径应与策略执行路径分离。 @@ -61,5 +55,5 @@ - 只给人工复核看的 artifact,用 `notification_only`。 - 仍然只是 sidecar 证据层的 artifact,用 `shadow_observer`。 -- 正在准备自动化的插件,用 `automation_candidate`,直到策略门槛也通过。 +- 如果准备自动消费某个插件行为,应晋级新的归属策略候选,而不是给插件仓位权限。 - 不再是新默认路径的插件,用 `deprecated_compatibility`,并避免出现在新的 runtime 默认值里。 diff --git a/src/quant_strategy_plugins/plugin_catalog.py b/src/quant_strategy_plugins/plugin_catalog.py index e9fcd72..fd47100 100644 --- a/src/quant_strategy_plugins/plugin_catalog.py +++ b/src/quant_strategy_plugins/plugin_catalog.py @@ -11,6 +11,7 @@ from .plugin_lineage import PLUGIN_LINEAGE_REGISTRY from .plugin_policies import ( PLUGIN_COMPATIBLE_STRATEGIES, + PLUGIN_DIRECT_POSITION_CONTROL_ALLOWED, PLUGIN_LIFECYCLE_POLICY_REGISTRY, PLUGIN_CONSUMPTION_POLICY_REGISTRY, ) @@ -34,7 +35,10 @@ def build_plugin_catalog() -> dict[str, Any]: for (policy_plugin, _), policy in PLUGIN_CONSUMPTION_POLICY_REGISTRY.items() if policy_plugin == plugin_id ] - position_allowed = any(policy.position_control_allowed for policy in policies) + position_allowed = bool( + PLUGIN_DIRECT_POSITION_CONTROL_ALLOWED + and any(policy.position_control_allowed for policy in policies) + ) entries.append( { "plugin_id": plugin_id, diff --git a/src/quant_strategy_plugins/plugin_policies.py b/src/quant_strategy_plugins/plugin_policies.py index 284ade1..9ec7d68 100644 --- a/src/quant_strategy_plugins/plugin_policies.py +++ b/src/quant_strategy_plugins/plugin_policies.py @@ -9,6 +9,9 @@ PLUGIN_LIFECYCLE_AUTOMATION_APPROVED = "automation_approved" PLUGIN_LIFECYCLE_NOTIFICATION_ONLY = "notification_only" PLUGIN_LIFECYCLE_DEPRECATED_COMPATIBILITY = "deprecated_compatibility" +# V1 artifacts retain position-control-shaped fields for deterministic replay, +# but the V2 sidecar boundary never grants direct allocation authority. +PLUGIN_DIRECT_POSITION_CONTROL_ALLOWED = False GENERAL_MARKET_REGIME_NOTIFICATION_TARGET = "market_regime_notification" @@ -79,11 +82,11 @@ class PluginLifecyclePolicy: PLUGIN_LIFECYCLE_POLICIES: tuple[PluginLifecyclePolicy, ...] = ( PluginLifecyclePolicy( plugin=PLUGIN_MARKET_REGIME_CONTROL, - lifecycle_stage=PLUGIN_LIFECYCLE_AUTOMATION_APPROVED, + lifecycle_stage=PLUGIN_LIFECYCLE_NOTIFICATION_ONLY, schema_versions=PLUGIN_SCHEMA_VERSIONS[PLUGIN_MARKET_REGIME_CONTROL], new_mount_allowed=True, replay_only=False, - description="Unified market-regime sidecar; automated consumption still requires per-strategy policy approval.", + description="Unified market-regime sidecar; outputs are notification/shadow metadata for strategy-owned evaluation.", ), PluginLifecyclePolicy( plugin=PLUGIN_PANIC_REVERSAL_SHADOW, @@ -132,10 +135,10 @@ class PluginLifecyclePolicy: plugin=PLUGIN_MARKET_REGIME_CONTROL, strategy="tqqq_growth_income", notification_allowed=True, - position_control_allowed=True, - evidence_status=EVIDENCE_AUTOMATION_APPROVED, + position_control_allowed=False, + evidence_status=EVIDENCE_NOTIFICATION_ONLY, since_version="strategy_plugins.v1", - description="Backtested automatic macro/crisis risk controls for the TQQQ growth-income strategy.", + description="Backtested macro/crisis observation for strategy-owned evaluation; no direct position control.", manual_review_notification_target=GENERAL_MARKET_REGIME_NOTIFICATION_TARGET, ), PluginConsumptionPolicy( @@ -172,10 +175,10 @@ class PluginLifecyclePolicy: plugin=PLUGIN_MARKET_REGIME_CONTROL, strategy="soxl_soxx_trend_income", notification_allowed=True, - position_control_allowed=True, - evidence_status=EVIDENCE_AUTOMATION_APPROVED, + position_control_allowed=False, + evidence_status=EVIDENCE_NOTIFICATION_ONLY, since_version="strategy_plugins.v1", - description="Backtested automatic macro/crisis risk controls for the SOXL/SOXX trend-income strategy.", + description="Backtested macro/crisis observation for strategy-owned evaluation; no direct position control.", manual_review_notification_target=GENERAL_MARKET_REGIME_NOTIFICATION_TARGET, ), PluginConsumptionPolicy( @@ -296,6 +299,7 @@ def extract_auditable_position_control_context(raw: Mapping[str, Any] | None) -> "PLUGIN_CONSUMPTION_POLICY_REGISTRY", "PLUGIN_CRISIS_RESPONSE_SHADOW", "PLUGIN_DEPRECATED_SUCCESSORS", + "PLUGIN_DIRECT_POSITION_CONTROL_ALLOWED", "PLUGIN_LIFECYCLE_AUTOMATION_APPROVED", "PLUGIN_LIFECYCLE_DEPRECATED_COMPATIBILITY", "PLUGIN_LIFECYCLE_NOTIFICATION_ONLY", diff --git a/src/quant_strategy_plugins/strategy_plugin_runner.py b/src/quant_strategy_plugins/strategy_plugin_runner.py index 00b06ce..f00c1b1 100644 --- a/src/quant_strategy_plugins/strategy_plugin_runner.py +++ b/src/quant_strategy_plugins/strategy_plugin_runner.py @@ -44,6 +44,7 @@ PLUGIN_CONSUMPTION_POLICY_REGISTRY, PLUGIN_CRISIS_RESPONSE_SHADOW, PLUGIN_DEPRECATED_SUCCESSORS, + PLUGIN_DIRECT_POSITION_CONTROL_ALLOWED, PLUGIN_LIFECYCLE_POLICIES, PLUGIN_LIFECYCLE_POLICY_REGISTRY, PLUGIN_MACRO_RISK_GOVERNOR, @@ -1357,7 +1358,11 @@ def _apply_plugin_contract( execution_controls["repository_allocation_mutation_allowed"] = False if consumption_policy is not None: execution_controls["notification_allowed"] = bool(consumption_policy.notification_allowed) - execution_controls["position_control_allowed"] = bool(consumption_policy.position_control_allowed) + position_control_allowed = bool( + PLUGIN_DIRECT_POSITION_CONTROL_ALLOWED + and consumption_policy.position_control_allowed + ) + execution_controls["position_control_allowed"] = position_control_allowed execution_controls["consumption_evidence_status"] = consumption_policy.evidence_status if consumption_policy.manual_review_notification_target: delegated_notification_target = consumption_policy.manual_review_notification_target @@ -1367,7 +1372,7 @@ def _apply_plugin_contract( f"notification_target:{delegated_notification_target}" ) execution_controls["manual_review_notification_authority"] = "plugin_notification_target" - if consumption_policy.position_control_allowed: + if position_control_allowed: execution_controls["capital_impact"] = "strategy_opt_in" execution_controls["strategy_runtime_metadata_allowed"] = True execution_controls["position_control_shadow_only"] = False diff --git a/tests/test_plugin_catalog.py b/tests/test_plugin_catalog.py index 8b9bd0d..50da385 100644 --- a/tests/test_plugin_catalog.py +++ b/tests/test_plugin_catalog.py @@ -19,10 +19,10 @@ def test_catalog_is_complete_inventory_and_never_grants_capital_authority() -> N assert entry["broker_order_allowed"] is False -def test_catalog_keeps_approved_policy_distinct_from_runtime_authority() -> None: +def test_catalog_closes_legacy_policy_position_authority() -> None: entries = {entry["plugin_id"]: entry for entry in build_plugin_catalog()["entries"]} - # A policy may permit a future strategy-side use, but the inventory itself - # never promotes a plugin or supplies a run-specific evidence package. - assert entries["market_regime_control"]["policy_position_control_allowed"] is True + # V1 policy fields remain readable, but V2 never grants direct position + # authority to a sidecar. + assert entries["market_regime_control"]["policy_position_control_allowed"] is False assert entries["market_regime_control"]["status"] == "DEFERRED" diff --git a/tests/test_plugin_policies.py b/tests/test_plugin_policies.py index e0c2661..c9d35e1 100644 --- a/tests/test_plugin_policies.py +++ b/tests/test_plugin_policies.py @@ -3,7 +3,7 @@ import quant_strategy_plugins.strategy_plugin_runner as strategy_plugin_runner from quant_strategy_plugins.plugin_policies import ( AUDITABLE_POSITION_CONTROL_FIELDS, - EVIDENCE_AUTOMATION_APPROVED, + EVIDENCE_NOTIFICATION_ONLY, GENERAL_MARKET_REGIME_NOTIFICATION_TARGET, PLUGIN_COMPATIBLE_STRATEGIES, PLUGIN_CONSUMPTION_POLICY_REGISTRY, @@ -16,12 +16,12 @@ ) -def test_market_regime_control_tqqq_policy_is_automation_approved() -> None: +def test_market_regime_control_tqqq_policy_is_notification_only() -> None: policy = PLUGIN_CONSUMPTION_POLICY_REGISTRY[(PLUGIN_MARKET_REGIME_CONTROL, "tqqq_growth_income")] - assert policy.evidence_status == EVIDENCE_AUTOMATION_APPROVED + assert policy.evidence_status == EVIDENCE_NOTIFICATION_ONLY assert policy.notification_allowed is True - assert policy.position_control_allowed is True + assert policy.position_control_allowed is False assert policy.manual_review_notification_target == GENERAL_MARKET_REGIME_NOTIFICATION_TARGET diff --git a/tests/test_strategy_plugin_runner.py b/tests/test_strategy_plugin_runner.py index bbf246f..ec05e59 100644 --- a/tests/test_strategy_plugin_runner.py +++ b/tests/test_strategy_plugin_runner.py @@ -10,7 +10,6 @@ from quant_strategy_plugins.crisis_response_research import ROUTE_TRUE_CRISIS from quant_strategy_plugins.market_regime_control_plugin import build_market_regime_control_signal from quant_strategy_plugins.strategy_plugin_runner import ( - EVIDENCE_AUTOMATION_APPROVED, EVIDENCE_NOTIFICATION_ONLY, GENERAL_MARKET_REGIME_NOTIFICATION_TARGET, PLUGIN_COMPATIBLE_NOTIFICATION_TARGETS, @@ -435,12 +434,12 @@ def test_strategy_plugin_runner_runs_unified_market_regime_control_for_tqqq(tmp_ ] == 0.0 ) - assert payload["execution_controls"]["strategy_runtime_metadata_allowed"] is True - assert payload["execution_controls"]["position_control_allowed"] is True - assert payload["execution_controls"]["capital_impact"] == "strategy_opt_in" - assert payload["execution_controls"]["position_control_shadow_only"] is False - assert payload["execution_controls"]["consumption_evidence_status"] == EVIDENCE_AUTOMATION_APPROVED - assert payload["consumption_policy"]["position_control_allowed"] is True + assert payload["execution_controls"]["strategy_runtime_metadata_allowed"] is False + assert payload["execution_controls"]["position_control_allowed"] is False + assert payload["execution_controls"]["capital_impact"] == "notification_only" + assert payload["execution_controls"]["position_control_shadow_only"] is True + assert payload["execution_controls"]["consumption_evidence_status"] == EVIDENCE_NOTIFICATION_ONLY + assert payload["consumption_policy"]["position_control_allowed"] is False assert payload["execution_controls"]["broker_order_allowed"] is False assert payload["execution_controls"]["live_allocation_mutation_allowed"] is False assert payload["localized_messages"]["labels"]["canonical_route"]["en-US"] == "Risk reduced" @@ -737,19 +736,11 @@ def test_strategy_plugin_runner_runs_unified_market_regime_control_for_soxl(tmp_ assert result["status"] == "ok" payload = json.loads((output_dir / "latest_signal.json").read_text(encoding="utf-8")) assert payload["strategy"] == SOXL_STRATEGY_NAME - assert payload["execution_controls"]["position_control_allowed"] is True - assert payload["execution_controls"]["strategy_runtime_metadata_allowed"] is True - assert payload["execution_controls"]["capital_impact"] == "strategy_opt_in" - assert payload["execution_controls"]["position_control_shadow_only"] is False - assert payload["execution_controls"]["auditable_position_control"] == { - "evidence_package_id": "pkg_001", - "evidence_valid_until": "2026-08-01T00:00:00Z", - "bounded_budget": { - "name": "position_control", - "amount": 0.5, - "unit": "fraction", - }, - } + assert payload["execution_controls"]["position_control_allowed"] is False + assert payload["execution_controls"]["strategy_runtime_metadata_allowed"] is False + assert payload["execution_controls"]["capital_impact"] == "notification_only" + assert payload["execution_controls"]["position_control_shadow_only"] is True + assert "auditable_position_control" not in payload["execution_controls"] assert payload["execution_controls"]["manual_review_notification_delegated"] is True assert ( payload["execution_controls"]["manual_review_notification_target"] @@ -762,7 +753,7 @@ def test_strategy_plugin_runner_runs_unified_market_regime_control_for_soxl(tmp_ volatility_delever_context = payload["position_control"]["volatility_delever_context"] assert volatility_delever_context["actionable_for_position_control"] is True assert volatility_delever_context["retention_profiles"]["soxl_step_rebound_0.25_0.50"]["retention_ratio"] == 0.0 - assert payload["position_control"]["auditable_position_control"] == payload["execution_controls"]["auditable_position_control"] + assert "auditable_position_control" not in payload["position_control"] def test_strategy_plugin_runner_marks_pending_strategy_mount_notification_only(tmp_path) -> None: @@ -884,10 +875,10 @@ def test_strategy_plugin_runner_contract_registry_prefers_unified_plugin() -> No ].position_control_allowed is False assert PLUGIN_CONSUMPTION_POLICY_REGISTRY[ (PLUGIN_MARKET_REGIME_CONTROL, STRATEGY_NAME) - ].position_control_allowed is True + ].position_control_allowed is False assert PLUGIN_CONSUMPTION_POLICY_REGISTRY[ (PLUGIN_MARKET_REGIME_CONTROL, SOXL_STRATEGY_NAME) - ].position_control_allowed is True + ].position_control_allowed is False for pending_strategy in ( "global_etf_rotation", "russell_1000_multi_factor_defensive",